Merge remote-tracking branch 'origin/main' into cache
# Conflicts: # crates/copilot/src/sign_in.rs # crates/gpui/src/window.rs # crates/workspace/src/pane_group.rs
This commit is contained in:
commit
1c260e6dfd
216 changed files with 4218 additions and 2389 deletions
|
@ -1,6 +1,6 @@
|
|||
use gpui::{ClickEvent, WindowContext};
|
||||
|
||||
/// A trait for elements that can be clicked.
|
||||
/// A trait for elements that can be clicked. Enables the use of the `on_click` method.
|
||||
pub trait Clickable {
|
||||
/// Sets the click handler that will fire whenever the element is clicked.
|
||||
fn on_click(self, handler: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self;
|
||||
|
|
|
@ -1,13 +1,28 @@
|
|||
use crate::prelude::*;
|
||||
use gpui::{img, Hsla, ImageSource, Img, IntoElement, Styled};
|
||||
|
||||
/// The shape of an [`Avatar`].
|
||||
#[derive(Debug, Default, PartialEq, Clone)]
|
||||
pub enum Shape {
|
||||
pub enum AvatarShape {
|
||||
/// The avatar is shown in a circle.
|
||||
#[default]
|
||||
Circle,
|
||||
/// The avatar is shown in a rectangle with rounded corners.
|
||||
RoundedRectangle,
|
||||
}
|
||||
|
||||
/// An element that renders a user avatar with customizable appearance options.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ui::{Avatar, AvatarShape};
|
||||
///
|
||||
/// Avatar::new("path/to/image.png")
|
||||
/// .shape(AvatarShape::Circle)
|
||||
/// .grayscale(true)
|
||||
/// .border_color(gpui::red());
|
||||
/// ```
|
||||
#[derive(IntoElement)]
|
||||
pub struct Avatar {
|
||||
image: Img,
|
||||
|
@ -18,7 +33,7 @@ pub struct Avatar {
|
|||
impl RenderOnce for Avatar {
|
||||
fn render(mut self, cx: &mut WindowContext) -> impl IntoElement {
|
||||
if self.image.style().corner_radii.top_left.is_none() {
|
||||
self = self.shape(Shape::Circle);
|
||||
self = self.shape(AvatarShape::Circle);
|
||||
}
|
||||
|
||||
let size = cx.rem_size();
|
||||
|
@ -66,14 +81,35 @@ impl Avatar {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn shape(mut self, shape: Shape) -> Self {
|
||||
/// Sets the shape of the avatar image.
|
||||
///
|
||||
/// This method allows the shape of the avatar to be specified using a [`Shape`].
|
||||
/// It modifies the corner radius of the image to match the specified shape.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ui::{Avatar, AvatarShape};
|
||||
///
|
||||
/// Avatar::new("path/to/image.png").shape(AvatarShape::Circle);
|
||||
/// ```
|
||||
pub fn shape(mut self, shape: AvatarShape) -> Self {
|
||||
self.image = match shape {
|
||||
Shape::Circle => self.image.rounded_full(),
|
||||
Shape::RoundedRectangle => self.image.rounded_md(),
|
||||
AvatarShape::Circle => self.image.rounded_full(),
|
||||
AvatarShape::RoundedRectangle => self.image.rounded_md(),
|
||||
};
|
||||
self
|
||||
}
|
||||
|
||||
/// Applies a grayscale filter to the avatar image.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ui::{Avatar, AvatarShape};
|
||||
///
|
||||
/// let avatar = Avatar::new("path/to/image.png").grayscale(true);
|
||||
/// ```
|
||||
pub fn grayscale(mut self, grayscale: bool) -> Self {
|
||||
self.image = self.image.grayscale(grayscale);
|
||||
self
|
||||
|
|
|
@ -2,11 +2,78 @@ use gpui::{AnyView, DefiniteLength};
|
|||
|
||||
use crate::{prelude::*, IconPosition, KeyBinding};
|
||||
use crate::{
|
||||
ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, Icon, IconSize, Label, LineHeightStyle,
|
||||
ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, IconName, IconSize, Label, LineHeightStyle,
|
||||
};
|
||||
|
||||
use super::button_icon::ButtonIcon;
|
||||
|
||||
/// An element that creates a button with a label and an optional icon.
|
||||
///
|
||||
/// Common buttons:
|
||||
/// - Label, Icon + Label: [`Button`] (this component)
|
||||
/// - Icon only: [`IconButton`]
|
||||
/// - Custom: [`ButtonLike`]
|
||||
///
|
||||
/// To create a more complex button than what the [`Button`] or [`IconButton`] components provide, use
|
||||
/// [`ButtonLike`] directly.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// **A button with a label**, is typically used in scenarios such as a form, where the button's label
|
||||
/// indicates what action will be performed when the button is clicked.
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// Button::new("button_id", "Click me!")
|
||||
/// .on_click(|event, cx| {
|
||||
/// // Handle click event
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// **A toggleable button**, is typically used in scenarios such as a toolbar,
|
||||
/// where the button's state indicates whether a feature is enabled or not, or
|
||||
/// a trigger for a popover menu, where clicking the button toggles the visibility of the menu.
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// Button::new("button_id", "Click me!")
|
||||
/// .icon(IconName::Check)
|
||||
/// .selected(true)
|
||||
/// .on_click(|event, cx| {
|
||||
/// // Handle click event
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// To change the style of the button when it is selected use the [`selected_style`][Button::selected_style] method.
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
/// use ui::TintColor;
|
||||
///
|
||||
/// Button::new("button_id", "Click me!")
|
||||
/// .selected(true)
|
||||
/// .selected_style(ButtonStyle::Tinted(TintColor::Accent))
|
||||
/// .on_click(|event, cx| {
|
||||
/// // Handle click event
|
||||
/// });
|
||||
/// ```
|
||||
/// This will create a button with a blue tinted background when selected.
|
||||
///
|
||||
/// **A full-width button**, is typically used in scenarios such as the bottom of a modal or form, where it occupies the entire width of its container.
|
||||
/// The button's content, including text and icons, is centered by default.
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// let button = Button::new("button_id", "Click me!")
|
||||
/// .full_width()
|
||||
/// .on_click(|event, cx| {
|
||||
/// // Handle click event
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
#[derive(IntoElement)]
|
||||
pub struct Button {
|
||||
base: ButtonLike,
|
||||
|
@ -14,15 +81,21 @@ pub struct Button {
|
|||
label_color: Option<Color>,
|
||||
label_size: Option<LabelSize>,
|
||||
selected_label: Option<SharedString>,
|
||||
icon: Option<Icon>,
|
||||
icon: Option<IconName>,
|
||||
icon_position: Option<IconPosition>,
|
||||
icon_size: Option<IconSize>,
|
||||
icon_color: Option<Color>,
|
||||
selected_icon: Option<Icon>,
|
||||
selected_icon: Option<IconName>,
|
||||
key_binding: Option<KeyBinding>,
|
||||
}
|
||||
|
||||
impl Button {
|
||||
/// Creates a new [`Button`] with a specified identifier and label.
|
||||
///
|
||||
/// This is the primary constructor for a [`Button`] component. It initializes
|
||||
/// the button with the provided identifier and label text, setting all other
|
||||
/// properties to their default values, which can be customized using the
|
||||
/// builder pattern methods provided by this struct.
|
||||
pub fn new(id: impl Into<ElementId>, label: impl Into<SharedString>) -> Self {
|
||||
Self {
|
||||
base: ButtonLike::new(id),
|
||||
|
@ -39,46 +112,55 @@ impl Button {
|
|||
}
|
||||
}
|
||||
|
||||
/// Sets the color of the button's label.
|
||||
pub fn color(mut self, label_color: impl Into<Option<Color>>) -> Self {
|
||||
self.label_color = label_color.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Defines the size of the button's label.
|
||||
pub fn label_size(mut self, label_size: impl Into<Option<LabelSize>>) -> Self {
|
||||
self.label_size = label_size.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the label used when the button is in a selected state.
|
||||
pub fn selected_label<L: Into<SharedString>>(mut self, label: impl Into<Option<L>>) -> Self {
|
||||
self.selected_label = label.into().map(Into::into);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn icon(mut self, icon: impl Into<Option<Icon>>) -> Self {
|
||||
/// Assigns an icon to the button.
|
||||
pub fn icon(mut self, icon: impl Into<Option<IconName>>) -> Self {
|
||||
self.icon = icon.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the position of the icon relative to the label.
|
||||
pub fn icon_position(mut self, icon_position: impl Into<Option<IconPosition>>) -> Self {
|
||||
self.icon_position = icon_position.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Specifies the size of the button's icon.
|
||||
pub fn icon_size(mut self, icon_size: impl Into<Option<IconSize>>) -> Self {
|
||||
self.icon_size = icon_size.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the color of the button's icon.
|
||||
pub fn icon_color(mut self, icon_color: impl Into<Option<Color>>) -> Self {
|
||||
self.icon_color = icon_color.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn selected_icon(mut self, icon: impl Into<Option<Icon>>) -> Self {
|
||||
/// Chooses an icon to display when the button is in a selected state.
|
||||
pub fn selected_icon(mut self, icon: impl Into<Option<IconName>>) -> Self {
|
||||
self.selected_icon = icon.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Binds a key combination to the button for keyboard shortcuts.
|
||||
pub fn key_binding(mut self, key_binding: impl Into<Option<KeyBinding>>) -> Self {
|
||||
self.key_binding = key_binding.into();
|
||||
self
|
||||
|
@ -86,6 +168,24 @@ impl Button {
|
|||
}
|
||||
|
||||
impl Selectable for Button {
|
||||
/// Sets the selected state of the button.
|
||||
///
|
||||
/// This method allows the selection state of the button to be specified.
|
||||
/// It modifies the button's appearance to reflect its selected state.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// Button::new("button_id", "Click me!")
|
||||
/// .selected(true)
|
||||
/// .on_click(|event, cx| {
|
||||
/// // Handle click event
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// Use [`selected_style`](Button::selected_style) to change the style of the button when it is selected.
|
||||
fn selected(mut self, selected: bool) -> Self {
|
||||
self.base = self.base.selected(selected);
|
||||
self
|
||||
|
@ -93,6 +193,22 @@ impl Selectable for Button {
|
|||
}
|
||||
|
||||
impl SelectableButton for Button {
|
||||
/// Sets the style for the button when selected.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
/// use ui::TintColor;
|
||||
///
|
||||
/// Button::new("button_id", "Click me!")
|
||||
/// .selected(true)
|
||||
/// .selected_style(ButtonStyle::Tinted(TintColor::Accent))
|
||||
/// .on_click(|event, cx| {
|
||||
/// // Handle click event
|
||||
/// });
|
||||
/// ```
|
||||
/// This results in a button with a blue tinted background when selected.
|
||||
fn selected_style(mut self, style: ButtonStyle) -> Self {
|
||||
self.base = self.base.selected_style(style);
|
||||
self
|
||||
|
@ -100,6 +216,24 @@ impl SelectableButton for Button {
|
|||
}
|
||||
|
||||
impl Disableable for Button {
|
||||
/// Disables the button.
|
||||
///
|
||||
/// This method allows the button to be disabled. When a button is disabled,
|
||||
/// it doesn't react to user interactions and its appearance is updated to reflect this.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// Button::new("button_id", "Click me!")
|
||||
/// .disabled(true)
|
||||
/// .on_click(|event, cx| {
|
||||
/// // Handle click event
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// This results in a button that is disabled and does not respond to click events.
|
||||
fn disabled(mut self, disabled: bool) -> Self {
|
||||
self.base = self.base.disabled(disabled);
|
||||
self
|
||||
|
@ -107,6 +241,7 @@ impl Disableable for Button {
|
|||
}
|
||||
|
||||
impl Clickable for Button {
|
||||
/// Sets the click event handler for the button.
|
||||
fn on_click(
|
||||
mut self,
|
||||
handler: impl Fn(&gpui::ClickEvent, &mut WindowContext) + 'static,
|
||||
|
@ -117,11 +252,44 @@ impl Clickable for Button {
|
|||
}
|
||||
|
||||
impl FixedWidth for Button {
|
||||
/// Sets a fixed width for the button.
|
||||
///
|
||||
/// This function allows a button to have a fixed width instead of automatically growing or shrinking.
|
||||
/// Sets a fixed width for the button.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// Button::new("button_id", "Click me!")
|
||||
/// .width(px(100.).into())
|
||||
/// .on_click(|event, cx| {
|
||||
/// // Handle click event
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// This sets the button's width to be exactly 100 pixels.
|
||||
fn width(mut self, width: DefiniteLength) -> Self {
|
||||
self.base = self.base.width(width);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the button to occupy the full width of its container.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// Button::new("button_id", "Click me!")
|
||||
/// .full_width()
|
||||
/// .on_click(|event, cx| {
|
||||
/// // Handle click event
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// This stretches the button to the full width of its container.
|
||||
fn full_width(mut self) -> Self {
|
||||
self.base = self.base.full_width();
|
||||
self
|
||||
|
@ -129,20 +297,45 @@ impl FixedWidth for Button {
|
|||
}
|
||||
|
||||
impl ButtonCommon for Button {
|
||||
/// Sets the button's id.
|
||||
fn id(&self) -> &ElementId {
|
||||
self.base.id()
|
||||
}
|
||||
|
||||
/// Sets the visual style of the button using a [`ButtonStyle`].
|
||||
fn style(mut self, style: ButtonStyle) -> Self {
|
||||
self.base = self.base.style(style);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the button's size using a [`ButtonSize`].
|
||||
fn size(mut self, size: ButtonSize) -> Self {
|
||||
self.base = self.base.size(size);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets a tooltip for the button.
|
||||
///
|
||||
/// This method allows a tooltip to be set for the button. The tooltip is a function that
|
||||
/// takes a mutable reference to a [`WindowContext`] and returns an [`AnyView`]. The tooltip
|
||||
/// is displayed when the user hovers over the button.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
/// use ui::Tooltip;
|
||||
///
|
||||
/// Button::new("button_id", "Click me!")
|
||||
/// .tooltip(move |cx| {
|
||||
/// Tooltip::text("This is a tooltip", cx)
|
||||
/// })
|
||||
/// .on_click(|event, cx| {
|
||||
/// // Handle click event
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// This will create a button with a tooltip that displays "This is a tooltip" when hovered over.
|
||||
fn tooltip(mut self, tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self {
|
||||
self.base = self.base.tooltip(tooltip);
|
||||
self
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{prelude::*, Icon, IconElement, IconSize};
|
||||
use crate::{prelude::*, Icon, IconName, IconSize};
|
||||
|
||||
/// An icon that appears within a button.
|
||||
///
|
||||
|
@ -6,17 +6,17 @@ use crate::{prelude::*, Icon, IconElement, IconSize};
|
|||
/// or as a standalone icon, like in [`IconButton`](crate::IconButton).
|
||||
#[derive(IntoElement)]
|
||||
pub(super) struct ButtonIcon {
|
||||
icon: Icon,
|
||||
icon: IconName,
|
||||
size: IconSize,
|
||||
color: Color,
|
||||
disabled: bool,
|
||||
selected: bool,
|
||||
selected_icon: Option<Icon>,
|
||||
selected_icon: Option<IconName>,
|
||||
selected_style: Option<ButtonStyle>,
|
||||
}
|
||||
|
||||
impl ButtonIcon {
|
||||
pub fn new(icon: Icon) -> Self {
|
||||
pub fn new(icon: IconName) -> Self {
|
||||
Self {
|
||||
icon,
|
||||
size: IconSize::default(),
|
||||
|
@ -44,7 +44,7 @@ impl ButtonIcon {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn selected_icon(mut self, icon: impl Into<Option<Icon>>) -> Self {
|
||||
pub fn selected_icon(mut self, icon: impl Into<Option<IconName>>) -> Self {
|
||||
self.selected_icon = icon.into();
|
||||
self
|
||||
}
|
||||
|
@ -88,6 +88,6 @@ impl RenderOnce for ButtonIcon {
|
|||
self.color
|
||||
};
|
||||
|
||||
IconElement::new(icon).size(self.size).color(icon_color)
|
||||
Icon::new(icon).size(self.size).color(icon_color)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,12 @@ use smallvec::SmallVec;
|
|||
|
||||
use crate::prelude::*;
|
||||
|
||||
/// A trait for buttons that can be Selected. Enables setting the [`ButtonStyle`] of a button when it is selected.
|
||||
pub trait SelectableButton: Selectable {
|
||||
fn selected_style(self, style: ButtonStyle) -> Self;
|
||||
}
|
||||
|
||||
/// A common set of traits all buttons must implement.
|
||||
pub trait ButtonCommon: Clickable + Disableable {
|
||||
/// A unique element ID to identify the button.
|
||||
fn id(&self) -> &ElementId;
|
||||
|
@ -93,6 +95,7 @@ impl From<ButtonStyle> for Color {
|
|||
}
|
||||
}
|
||||
|
||||
/// The visual appearance of a button.
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
|
||||
pub enum ButtonStyle {
|
||||
/// A filled button with a solid background color. Provides emphasis versus
|
||||
|
@ -260,8 +263,9 @@ impl ButtonStyle {
|
|||
}
|
||||
}
|
||||
|
||||
/// ButtonSize can also be used to help build non-button elements
|
||||
/// that are consistently sized with buttons.
|
||||
/// The height of a button.
|
||||
///
|
||||
/// Can also be used to size non-button elements to align with [`Button`]s.
|
||||
#[derive(Default, PartialEq, Clone, Copy)]
|
||||
pub enum ButtonSize {
|
||||
Large,
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
use gpui::{AnyView, DefiniteLength};
|
||||
|
||||
use crate::{prelude::*, SelectableButton};
|
||||
use crate::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, Icon, IconSize};
|
||||
use crate::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, IconName, IconSize};
|
||||
|
||||
use super::button_icon::ButtonIcon;
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct IconButton {
|
||||
base: ButtonLike,
|
||||
icon: Icon,
|
||||
icon: IconName,
|
||||
icon_size: IconSize,
|
||||
icon_color: Color,
|
||||
selected_icon: Option<Icon>,
|
||||
selected_icon: Option<IconName>,
|
||||
}
|
||||
|
||||
impl IconButton {
|
||||
pub fn new(id: impl Into<ElementId>, icon: Icon) -> Self {
|
||||
pub fn new(id: impl Into<ElementId>, icon: IconName) -> Self {
|
||||
Self {
|
||||
base: ButtonLike::new(id),
|
||||
icon,
|
||||
|
@ -35,7 +35,7 @@ impl IconButton {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn selected_icon(mut self, icon: impl Into<Option<Icon>>) -> Self {
|
||||
pub fn selected_icon(mut self, icon: impl Into<Option<IconName>>) -> Self {
|
||||
self.selected_icon = icon.into();
|
||||
self
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use gpui::{div, prelude::*, ElementId, IntoElement, Styled, WindowContext};
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{Color, Icon, IconElement, Selection};
|
||||
use crate::{Color, Icon, IconName, Selection};
|
||||
|
||||
pub type CheckHandler = Box<dyn Fn(&Selection, &mut WindowContext) + 'static>;
|
||||
|
||||
|
@ -47,7 +47,7 @@ impl RenderOnce for Checkbox {
|
|||
let group_id = format!("checkbox_group_{:?}", self.id);
|
||||
|
||||
let icon = match self.checked {
|
||||
Selection::Selected => Some(IconElement::new(Icon::Check).size(IconSize::Small).color(
|
||||
Selection::Selected => Some(Icon::new(IconName::Check).size(IconSize::Small).color(
|
||||
if self.disabled {
|
||||
Color::Disabled
|
||||
} else {
|
||||
|
@ -55,7 +55,7 @@ impl RenderOnce for Checkbox {
|
|||
},
|
||||
)),
|
||||
Selection::Indeterminate => Some(
|
||||
IconElement::new(Icon::Dash)
|
||||
Icon::new(IconName::Dash)
|
||||
.size(IconSize::Small)
|
||||
.color(if self.disabled {
|
||||
Color::Disabled
|
||||
|
@ -73,7 +73,7 @@ impl RenderOnce for Checkbox {
|
|||
// - a previously agreed to license that has been updated
|
||||
//
|
||||
// For the sake of styles we treat the indeterminate state as selected,
|
||||
// but it's icon will be different.
|
||||
// but its icon will be different.
|
||||
let selected =
|
||||
self.checked == Selection::Selected || self.checked == Selection::Indeterminate;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
h_stack, prelude::*, v_stack, Icon, IconElement, KeyBinding, Label, List, ListItem,
|
||||
ListSeparator, ListSubHeader,
|
||||
h_stack, prelude::*, v_stack, Icon, IconName, KeyBinding, Label, List, ListItem, ListSeparator,
|
||||
ListSubHeader,
|
||||
};
|
||||
use gpui::{
|
||||
px, Action, AnyElement, AppContext, DismissEvent, EventEmitter, FocusHandle, FocusableView,
|
||||
|
@ -14,7 +14,7 @@ enum ContextMenuItem {
|
|||
Header(SharedString),
|
||||
Entry {
|
||||
label: SharedString,
|
||||
icon: Option<Icon>,
|
||||
icon: Option<IconName>,
|
||||
handler: Rc<dyn Fn(&mut WindowContext)>,
|
||||
action: Option<Box<dyn Action>>,
|
||||
},
|
||||
|
@ -117,7 +117,7 @@ impl ContextMenu {
|
|||
label: label.into(),
|
||||
action: Some(action.boxed_clone()),
|
||||
handler: Rc::new(move |cx| cx.dispatch_action(action.boxed_clone())),
|
||||
icon: Some(Icon::Link),
|
||||
icon: Some(IconName::Link),
|
||||
});
|
||||
self
|
||||
}
|
||||
|
@ -280,7 +280,7 @@ impl Render for ContextMenu {
|
|||
h_stack()
|
||||
.gap_1()
|
||||
.child(Label::new(label.clone()))
|
||||
.child(IconElement::new(*icon))
|
||||
.child(Icon::new(*icon))
|
||||
.into_any_element()
|
||||
} else {
|
||||
Label::new(label.clone()).into_any_element()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use gpui::ClickEvent;
|
||||
|
||||
use crate::{prelude::*, Color, Icon, IconButton, IconSize};
|
||||
use crate::{prelude::*, Color, IconButton, IconName, IconSize};
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct Disclosure {
|
||||
|
@ -32,8 +32,8 @@ impl RenderOnce for Disclosure {
|
|||
IconButton::new(
|
||||
self.id,
|
||||
match self.is_open {
|
||||
true => Icon::ChevronDown,
|
||||
false => Icon::ChevronRight,
|
||||
true => IconName::ChevronDown,
|
||||
false => IconName::ChevronRight,
|
||||
},
|
||||
)
|
||||
.icon_color(Color::Muted)
|
||||
|
|
|
@ -7,6 +7,7 @@ enum DividerDirection {
|
|||
Vertical,
|
||||
}
|
||||
|
||||
/// The color of a [`Divider`].
|
||||
#[derive(Default)]
|
||||
pub enum DividerColor {
|
||||
Border,
|
||||
|
|
|
@ -22,7 +22,7 @@ impl IconSize {
|
|||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone, EnumIter)]
|
||||
pub enum Icon {
|
||||
pub enum IconName {
|
||||
Ai,
|
||||
ArrowDown,
|
||||
ArrowLeft,
|
||||
|
@ -111,118 +111,108 @@ pub enum Icon {
|
|||
ZedXCopilot,
|
||||
}
|
||||
|
||||
impl Icon {
|
||||
impl IconName {
|
||||
pub fn path(self) -> &'static str {
|
||||
match self {
|
||||
Icon::Ai => "icons/ai.svg",
|
||||
Icon::ArrowDown => "icons/arrow_down.svg",
|
||||
Icon::ArrowLeft => "icons/arrow_left.svg",
|
||||
Icon::ArrowRight => "icons/arrow_right.svg",
|
||||
Icon::ArrowUp => "icons/arrow_up.svg",
|
||||
Icon::ArrowUpRight => "icons/arrow_up_right.svg",
|
||||
Icon::ArrowCircle => "icons/arrow_circle.svg",
|
||||
Icon::AtSign => "icons/at_sign.svg",
|
||||
Icon::AudioOff => "icons/speaker_off.svg",
|
||||
Icon::AudioOn => "icons/speaker_loud.svg",
|
||||
Icon::Backspace => "icons/backspace.svg",
|
||||
Icon::Bell => "icons/bell.svg",
|
||||
Icon::BellOff => "icons/bell_off.svg",
|
||||
Icon::BellRing => "icons/bell_ring.svg",
|
||||
Icon::Bolt => "icons/bolt.svg",
|
||||
Icon::CaseSensitive => "icons/case_insensitive.svg",
|
||||
Icon::Check => "icons/check.svg",
|
||||
Icon::ChevronDown => "icons/chevron_down.svg",
|
||||
Icon::ChevronLeft => "icons/chevron_left.svg",
|
||||
Icon::ChevronRight => "icons/chevron_right.svg",
|
||||
Icon::ChevronUp => "icons/chevron_up.svg",
|
||||
Icon::Close => "icons/x.svg",
|
||||
Icon::Collab => "icons/user_group_16.svg",
|
||||
Icon::Command => "icons/command.svg",
|
||||
Icon::Control => "icons/control.svg",
|
||||
Icon::Copilot => "icons/copilot.svg",
|
||||
Icon::CopilotDisabled => "icons/copilot_disabled.svg",
|
||||
Icon::CopilotError => "icons/copilot_error.svg",
|
||||
Icon::CopilotInit => "icons/copilot_init.svg",
|
||||
Icon::Copy => "icons/copy.svg",
|
||||
Icon::Dash => "icons/dash.svg",
|
||||
Icon::Delete => "icons/delete.svg",
|
||||
Icon::Disconnected => "icons/disconnected.svg",
|
||||
Icon::Ellipsis => "icons/ellipsis.svg",
|
||||
Icon::Envelope => "icons/feedback.svg",
|
||||
Icon::Escape => "icons/escape.svg",
|
||||
Icon::ExclamationTriangle => "icons/warning.svg",
|
||||
Icon::Exit => "icons/exit.svg",
|
||||
Icon::ExternalLink => "icons/external_link.svg",
|
||||
Icon::File => "icons/file.svg",
|
||||
Icon::FileDoc => "icons/file_icons/book.svg",
|
||||
Icon::FileGeneric => "icons/file_icons/file.svg",
|
||||
Icon::FileGit => "icons/file_icons/git.svg",
|
||||
Icon::FileLock => "icons/file_icons/lock.svg",
|
||||
Icon::FileRust => "icons/file_icons/rust.svg",
|
||||
Icon::FileToml => "icons/file_icons/toml.svg",
|
||||
Icon::FileTree => "icons/project.svg",
|
||||
Icon::Filter => "icons/filter.svg",
|
||||
Icon::Folder => "icons/file_icons/folder.svg",
|
||||
Icon::FolderOpen => "icons/file_icons/folder_open.svg",
|
||||
Icon::FolderX => "icons/stop_sharing.svg",
|
||||
Icon::Github => "icons/github.svg",
|
||||
Icon::Hash => "icons/hash.svg",
|
||||
Icon::InlayHint => "icons/inlay_hint.svg",
|
||||
Icon::Link => "icons/link.svg",
|
||||
Icon::MagicWand => "icons/magic_wand.svg",
|
||||
Icon::MagnifyingGlass => "icons/magnifying_glass.svg",
|
||||
Icon::MailOpen => "icons/mail_open.svg",
|
||||
Icon::Maximize => "icons/maximize.svg",
|
||||
Icon::Menu => "icons/menu.svg",
|
||||
Icon::MessageBubbles => "icons/conversations.svg",
|
||||
Icon::Mic => "icons/mic.svg",
|
||||
Icon::MicMute => "icons/mic_mute.svg",
|
||||
Icon::Minimize => "icons/minimize.svg",
|
||||
Icon::Option => "icons/option.svg",
|
||||
Icon::PageDown => "icons/page_down.svg",
|
||||
Icon::PageUp => "icons/page_up.svg",
|
||||
Icon::Plus => "icons/plus.svg",
|
||||
Icon::Public => "icons/public.svg",
|
||||
Icon::Quote => "icons/quote.svg",
|
||||
Icon::Replace => "icons/replace.svg",
|
||||
Icon::ReplaceAll => "icons/replace_all.svg",
|
||||
Icon::ReplaceNext => "icons/replace_next.svg",
|
||||
Icon::Return => "icons/return.svg",
|
||||
Icon::Screen => "icons/desktop.svg",
|
||||
Icon::SelectAll => "icons/select_all.svg",
|
||||
Icon::Shift => "icons/shift.svg",
|
||||
Icon::Snip => "icons/snip.svg",
|
||||
Icon::Space => "icons/space.svg",
|
||||
Icon::Split => "icons/split.svg",
|
||||
Icon::Tab => "icons/tab.svg",
|
||||
Icon::Terminal => "icons/terminal.svg",
|
||||
Icon::Update => "icons/update.svg",
|
||||
Icon::WholeWord => "icons/word_search.svg",
|
||||
Icon::XCircle => "icons/error.svg",
|
||||
Icon::ZedXCopilot => "icons/zed_x_copilot.svg",
|
||||
IconName::Ai => "icons/ai.svg",
|
||||
IconName::ArrowDown => "icons/arrow_down.svg",
|
||||
IconName::ArrowLeft => "icons/arrow_left.svg",
|
||||
IconName::ArrowRight => "icons/arrow_right.svg",
|
||||
IconName::ArrowUp => "icons/arrow_up.svg",
|
||||
IconName::ArrowUpRight => "icons/arrow_up_right.svg",
|
||||
IconName::ArrowCircle => "icons/arrow_circle.svg",
|
||||
IconName::AtSign => "icons/at_sign.svg",
|
||||
IconName::AudioOff => "icons/speaker_off.svg",
|
||||
IconName::AudioOn => "icons/speaker_loud.svg",
|
||||
IconName::Backspace => "icons/backspace.svg",
|
||||
IconName::Bell => "icons/bell.svg",
|
||||
IconName::BellOff => "icons/bell_off.svg",
|
||||
IconName::BellRing => "icons/bell_ring.svg",
|
||||
IconName::Bolt => "icons/bolt.svg",
|
||||
IconName::CaseSensitive => "icons/case_insensitive.svg",
|
||||
IconName::Check => "icons/check.svg",
|
||||
IconName::ChevronDown => "icons/chevron_down.svg",
|
||||
IconName::ChevronLeft => "icons/chevron_left.svg",
|
||||
IconName::ChevronRight => "icons/chevron_right.svg",
|
||||
IconName::ChevronUp => "icons/chevron_up.svg",
|
||||
IconName::Close => "icons/x.svg",
|
||||
IconName::Collab => "icons/user_group_16.svg",
|
||||
IconName::Command => "icons/command.svg",
|
||||
IconName::Control => "icons/control.svg",
|
||||
IconName::Copilot => "icons/copilot.svg",
|
||||
IconName::CopilotDisabled => "icons/copilot_disabled.svg",
|
||||
IconName::CopilotError => "icons/copilot_error.svg",
|
||||
IconName::CopilotInit => "icons/copilot_init.svg",
|
||||
IconName::Copy => "icons/copy.svg",
|
||||
IconName::Dash => "icons/dash.svg",
|
||||
IconName::Delete => "icons/delete.svg",
|
||||
IconName::Disconnected => "icons/disconnected.svg",
|
||||
IconName::Ellipsis => "icons/ellipsis.svg",
|
||||
IconName::Envelope => "icons/feedback.svg",
|
||||
IconName::Escape => "icons/escape.svg",
|
||||
IconName::ExclamationTriangle => "icons/warning.svg",
|
||||
IconName::Exit => "icons/exit.svg",
|
||||
IconName::ExternalLink => "icons/external_link.svg",
|
||||
IconName::File => "icons/file.svg",
|
||||
IconName::FileDoc => "icons/file_icons/book.svg",
|
||||
IconName::FileGeneric => "icons/file_icons/file.svg",
|
||||
IconName::FileGit => "icons/file_icons/git.svg",
|
||||
IconName::FileLock => "icons/file_icons/lock.svg",
|
||||
IconName::FileRust => "icons/file_icons/rust.svg",
|
||||
IconName::FileToml => "icons/file_icons/toml.svg",
|
||||
IconName::FileTree => "icons/project.svg",
|
||||
IconName::Filter => "icons/filter.svg",
|
||||
IconName::Folder => "icons/file_icons/folder.svg",
|
||||
IconName::FolderOpen => "icons/file_icons/folder_open.svg",
|
||||
IconName::FolderX => "icons/stop_sharing.svg",
|
||||
IconName::Github => "icons/github.svg",
|
||||
IconName::Hash => "icons/hash.svg",
|
||||
IconName::InlayHint => "icons/inlay_hint.svg",
|
||||
IconName::Link => "icons/link.svg",
|
||||
IconName::MagicWand => "icons/magic_wand.svg",
|
||||
IconName::MagnifyingGlass => "icons/magnifying_glass.svg",
|
||||
IconName::MailOpen => "icons/mail_open.svg",
|
||||
IconName::Maximize => "icons/maximize.svg",
|
||||
IconName::Menu => "icons/menu.svg",
|
||||
IconName::MessageBubbles => "icons/conversations.svg",
|
||||
IconName::Mic => "icons/mic.svg",
|
||||
IconName::MicMute => "icons/mic_mute.svg",
|
||||
IconName::Minimize => "icons/minimize.svg",
|
||||
IconName::Option => "icons/option.svg",
|
||||
IconName::PageDown => "icons/page_down.svg",
|
||||
IconName::PageUp => "icons/page_up.svg",
|
||||
IconName::Plus => "icons/plus.svg",
|
||||
IconName::Public => "icons/public.svg",
|
||||
IconName::Quote => "icons/quote.svg",
|
||||
IconName::Replace => "icons/replace.svg",
|
||||
IconName::ReplaceAll => "icons/replace_all.svg",
|
||||
IconName::ReplaceNext => "icons/replace_next.svg",
|
||||
IconName::Return => "icons/return.svg",
|
||||
IconName::Screen => "icons/desktop.svg",
|
||||
IconName::SelectAll => "icons/select_all.svg",
|
||||
IconName::Shift => "icons/shift.svg",
|
||||
IconName::Snip => "icons/snip.svg",
|
||||
IconName::Space => "icons/space.svg",
|
||||
IconName::Split => "icons/split.svg",
|
||||
IconName::Tab => "icons/tab.svg",
|
||||
IconName::Terminal => "icons/terminal.svg",
|
||||
IconName::Update => "icons/update.svg",
|
||||
IconName::WholeWord => "icons/word_search.svg",
|
||||
IconName::XCircle => "icons/error.svg",
|
||||
IconName::ZedXCopilot => "icons/zed_x_copilot.svg",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct IconElement {
|
||||
pub struct Icon {
|
||||
path: SharedString,
|
||||
color: Color,
|
||||
size: IconSize,
|
||||
}
|
||||
|
||||
impl RenderOnce for IconElement {
|
||||
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
||||
svg()
|
||||
.size(self.size.rems())
|
||||
.flex_none()
|
||||
.path(self.path)
|
||||
.text_color(self.color.color(cx))
|
||||
}
|
||||
}
|
||||
|
||||
impl IconElement {
|
||||
pub fn new(icon: Icon) -> Self {
|
||||
impl Icon {
|
||||
pub fn new(icon: IconName) -> Self {
|
||||
Self {
|
||||
path: icon.path().into(),
|
||||
color: Color::default(),
|
||||
|
@ -248,3 +238,13 @@ impl IconElement {
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for Icon {
|
||||
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
||||
svg()
|
||||
.size(self.size.rems())
|
||||
.flex_none()
|
||||
.path(self.path)
|
||||
.text_color(self.color.color(cx))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{h_stack, prelude::*, Icon, IconElement, IconSize};
|
||||
use crate::{h_stack, prelude::*, Icon, IconName, IconSize};
|
||||
use gpui::{relative, rems, Action, FocusHandle, IntoElement, Keystroke};
|
||||
|
||||
#[derive(IntoElement, Clone)]
|
||||
|
@ -26,16 +26,16 @@ impl RenderOnce for KeyBinding {
|
|||
.text_color(cx.theme().colors().text_muted)
|
||||
.when(keystroke.modifiers.function, |el| el.child(Key::new("fn")))
|
||||
.when(keystroke.modifiers.control, |el| {
|
||||
el.child(KeyIcon::new(Icon::Control))
|
||||
el.child(KeyIcon::new(IconName::Control))
|
||||
})
|
||||
.when(keystroke.modifiers.alt, |el| {
|
||||
el.child(KeyIcon::new(Icon::Option))
|
||||
el.child(KeyIcon::new(IconName::Option))
|
||||
})
|
||||
.when(keystroke.modifiers.command, |el| {
|
||||
el.child(KeyIcon::new(Icon::Command))
|
||||
el.child(KeyIcon::new(IconName::Command))
|
||||
})
|
||||
.when(keystroke.modifiers.shift, |el| {
|
||||
el.child(KeyIcon::new(Icon::Shift))
|
||||
el.child(KeyIcon::new(IconName::Shift))
|
||||
})
|
||||
.when_some(key_icon, |el, icon| el.child(KeyIcon::new(icon)))
|
||||
.when(key_icon.is_none(), |el| {
|
||||
|
@ -62,21 +62,21 @@ impl KeyBinding {
|
|||
Some(Self::new(key_binding))
|
||||
}
|
||||
|
||||
fn icon_for_key(keystroke: &Keystroke) -> Option<Icon> {
|
||||
fn icon_for_key(keystroke: &Keystroke) -> Option<IconName> {
|
||||
match keystroke.key.as_str() {
|
||||
"left" => Some(Icon::ArrowLeft),
|
||||
"right" => Some(Icon::ArrowRight),
|
||||
"up" => Some(Icon::ArrowUp),
|
||||
"down" => Some(Icon::ArrowDown),
|
||||
"backspace" => Some(Icon::Backspace),
|
||||
"delete" => Some(Icon::Delete),
|
||||
"return" => Some(Icon::Return),
|
||||
"enter" => Some(Icon::Return),
|
||||
"tab" => Some(Icon::Tab),
|
||||
"space" => Some(Icon::Space),
|
||||
"escape" => Some(Icon::Escape),
|
||||
"pagedown" => Some(Icon::PageDown),
|
||||
"pageup" => Some(Icon::PageUp),
|
||||
"left" => Some(IconName::ArrowLeft),
|
||||
"right" => Some(IconName::ArrowRight),
|
||||
"up" => Some(IconName::ArrowUp),
|
||||
"down" => Some(IconName::ArrowDown),
|
||||
"backspace" => Some(IconName::Backspace),
|
||||
"delete" => Some(IconName::Delete),
|
||||
"return" => Some(IconName::Return),
|
||||
"enter" => Some(IconName::Return),
|
||||
"tab" => Some(IconName::Tab),
|
||||
"space" => Some(IconName::Space),
|
||||
"escape" => Some(IconName::Escape),
|
||||
"pagedown" => Some(IconName::PageDown),
|
||||
"pageup" => Some(IconName::PageUp),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -120,13 +120,13 @@ impl Key {
|
|||
|
||||
#[derive(IntoElement)]
|
||||
pub struct KeyIcon {
|
||||
icon: Icon,
|
||||
icon: IconName,
|
||||
}
|
||||
|
||||
impl RenderOnce for KeyIcon {
|
||||
fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
|
||||
div().w(rems(14. / 16.)).child(
|
||||
IconElement::new(self.icon)
|
||||
Icon::new(self.icon)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
|
@ -134,7 +134,7 @@ impl RenderOnce for KeyIcon {
|
|||
}
|
||||
|
||||
impl KeyIcon {
|
||||
pub fn new(icon: Icon) -> Self {
|
||||
pub fn new(icon: IconName) -> Self {
|
||||
Self { icon }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,34 @@ use gpui::WindowContext;
|
|||
|
||||
use crate::{prelude::*, LabelCommon, LabelLike, LabelSize, LineHeightStyle};
|
||||
|
||||
/// A struct representing a label element in the UI.
|
||||
///
|
||||
/// The `Label` struct stores the label text and common properties for a label element.
|
||||
/// It provides methods for modifying these properties.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// Label::new("Hello, World!");
|
||||
/// ```
|
||||
///
|
||||
/// **A colored label**, for example labeling a dangerous action:
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// let my_label = Label::new("Delete").color(Color::Error);
|
||||
/// ```
|
||||
///
|
||||
/// **A label with a strikethrough**, for example labeling something that has been deleted:
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// let my_label = Label::new("Deleted").strikethrough(true);
|
||||
/// ```
|
||||
#[derive(IntoElement)]
|
||||
pub struct Label {
|
||||
base: LabelLike,
|
||||
|
@ -9,6 +37,15 @@ pub struct Label {
|
|||
}
|
||||
|
||||
impl Label {
|
||||
/// Create a new [`Label`] with the given text.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// let my_label = Label::new("Hello, World!");
|
||||
/// ```
|
||||
pub fn new(label: impl Into<SharedString>) -> Self {
|
||||
Self {
|
||||
base: LabelLike::new(),
|
||||
|
@ -18,21 +55,57 @@ impl Label {
|
|||
}
|
||||
|
||||
impl LabelCommon for Label {
|
||||
/// Sets the size of the label using a [`LabelSize`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// let my_label = Label::new("Hello, World!").size(LabelSize::Small);
|
||||
/// ```
|
||||
fn size(mut self, size: LabelSize) -> Self {
|
||||
self.base = self.base.size(size);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the line height style of the label using a [`LineHeightStyle`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// let my_label = Label::new("Hello, World!").line_height_style(LineHeightStyle::UiLabel);
|
||||
/// ```
|
||||
fn line_height_style(mut self, line_height_style: LineHeightStyle) -> Self {
|
||||
self.base = self.base.line_height_style(line_height_style);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the color of the label using a [`Color`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// let my_label = Label::new("Hello, World!").color(Color::Accent);
|
||||
/// ```
|
||||
fn color(mut self, color: Color) -> Self {
|
||||
self.base = self.base.color(color);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the strikethrough property of the label.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// let my_label = Label::new("Hello, World!").strikethrough(true);
|
||||
/// ```
|
||||
fn strikethrough(mut self, strikethrough: bool) -> Self {
|
||||
self.base = self.base.strikethrough(strikethrough);
|
||||
self
|
||||
|
|
|
@ -19,10 +19,18 @@ pub enum LineHeightStyle {
|
|||
UiLabel,
|
||||
}
|
||||
|
||||
/// A common set of traits all labels must implement.
|
||||
pub trait LabelCommon {
|
||||
/// Sets the size of the label using a [`LabelSize`].
|
||||
fn size(self, size: LabelSize) -> Self;
|
||||
|
||||
/// Sets the line height style of the label using a [`LineHeightStyle`].
|
||||
fn line_height_style(self, line_height_style: LineHeightStyle) -> Self;
|
||||
|
||||
/// Sets the color of the label using a [`Color`].
|
||||
fn color(self, color: Color) -> Self;
|
||||
|
||||
/// Sets the strikethrough property of the label.
|
||||
fn strikethrough(self, strikethrough: bool) -> Self;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use crate::prelude::*;
|
||||
use crate::{h_stack, Icon, IconElement, IconSize, Label};
|
||||
use crate::{h_stack, Icon, IconName, IconSize, Label};
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct ListSubHeader {
|
||||
label: SharedString,
|
||||
start_slot: Option<Icon>,
|
||||
start_slot: Option<IconName>,
|
||||
inset: bool,
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ impl ListSubHeader {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn left_icon(mut self, left_icon: Option<Icon>) -> Self {
|
||||
pub fn left_icon(mut self, left_icon: Option<IconName>) -> Self {
|
||||
self.start_slot = left_icon;
|
||||
self
|
||||
}
|
||||
|
@ -40,11 +40,10 @@ impl RenderOnce for ListSubHeader {
|
|||
.flex()
|
||||
.gap_1()
|
||||
.items_center()
|
||||
.children(self.start_slot.map(|i| {
|
||||
IconElement::new(i)
|
||||
.color(Color::Muted)
|
||||
.size(IconSize::Small)
|
||||
}))
|
||||
.children(
|
||||
self.start_slot
|
||||
.map(|i| Icon::new(i).color(Color::Muted).size(IconSize::Small)),
|
||||
)
|
||||
.child(Label::new(self.label.clone()).color(Color::Muted)),
|
||||
),
|
||||
)
|
||||
|
|
|
@ -108,6 +108,7 @@ impl<M: ManagedView> PopoverMenu<M> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a [`PopoverMenu`]
|
||||
pub fn popover_menu<M: ManagedView>(id: impl Into<ElementId>) -> PopoverMenu<M> {
|
||||
PopoverMenu {
|
||||
id: id.into(),
|
||||
|
|
|
@ -39,6 +39,7 @@ impl<M: ManagedView> RightClickMenu<M> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a [`RightClickMenu`]
|
||||
pub fn right_click_menu<M: ManagedView>(id: impl Into<ElementId>) -> RightClickMenu<M> {
|
||||
RightClickMenu {
|
||||
id: id.into(),
|
||||
|
|
|
@ -2,17 +2,13 @@ use gpui::{div, Div};
|
|||
|
||||
use crate::StyledExt;
|
||||
|
||||
/// Horizontally stacks elements.
|
||||
///
|
||||
/// Sets `flex()`, `flex_row()`, `items_center()`
|
||||
/// Horizontally stacks elements. Sets `flex()`, `flex_row()`, `items_center()`
|
||||
#[track_caller]
|
||||
pub fn h_stack() -> Div {
|
||||
div().h_flex()
|
||||
}
|
||||
|
||||
/// Vertically stacks elements.
|
||||
///
|
||||
/// Sets `flex()`, `flex_col()`
|
||||
/// Vertically stacks elements. Sets `flex()`, `flex_col()`
|
||||
#[track_caller]
|
||||
pub fn v_stack() -> Div {
|
||||
div().v_flex()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use gpui::Render;
|
||||
use story::Story;
|
||||
|
||||
use crate::{prelude::*, Icon};
|
||||
use crate::{prelude::*, IconName};
|
||||
use crate::{Button, ButtonStyle};
|
||||
|
||||
pub struct ButtonStory;
|
||||
|
@ -23,12 +23,12 @@ impl Render for ButtonStory {
|
|||
.child(Story::label("With `label_color`"))
|
||||
.child(Button::new("filled_with_label_color", "Click me").color(Color::Created))
|
||||
.child(Story::label("With `icon`"))
|
||||
.child(Button::new("filled_with_icon", "Click me").icon(Icon::FileGit))
|
||||
.child(Button::new("filled_with_icon", "Click me").icon(IconName::FileGit))
|
||||
.child(Story::label("Selected with `icon`"))
|
||||
.child(
|
||||
Button::new("filled_and_selected_with_icon", "Click me")
|
||||
.selected(true)
|
||||
.icon(Icon::FileGit),
|
||||
.icon(IconName::FileGit),
|
||||
)
|
||||
.child(Story::label("Default (Subtle)"))
|
||||
.child(Button::new("default_subtle", "Click me").style(ButtonStyle::Subtle))
|
||||
|
|
|
@ -3,17 +3,17 @@ use story::Story;
|
|||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{Icon, IconElement};
|
||||
use crate::{Icon, IconName};
|
||||
|
||||
pub struct IconStory;
|
||||
|
||||
impl Render for IconStory {
|
||||
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
let icons = Icon::iter();
|
||||
let icons = IconName::iter();
|
||||
|
||||
Story::container()
|
||||
.child(Story::title_for::<IconElement>())
|
||||
.child(Story::title_for::<Icon>())
|
||||
.child(Story::label("All Icons"))
|
||||
.child(div().flex().gap_3().children(icons.map(IconElement::new)))
|
||||
.child(div().flex().gap_3().children(icons.map(Icon::new)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use gpui::Render;
|
|||
use story::{StoryContainer, StoryItem, StorySection};
|
||||
|
||||
use crate::{prelude::*, Tooltip};
|
||||
use crate::{Icon, IconButton};
|
||||
use crate::{IconButton, IconName};
|
||||
|
||||
pub struct IconButtonStory;
|
||||
|
||||
|
@ -10,7 +10,7 @@ impl Render for IconButtonStory {
|
|||
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
let default_button = StoryItem::new(
|
||||
"Default",
|
||||
IconButton::new("default_icon_button", Icon::Hash),
|
||||
IconButton::new("default_icon_button", IconName::Hash),
|
||||
)
|
||||
.description("Displays an icon button.")
|
||||
.usage(
|
||||
|
@ -21,7 +21,7 @@ impl Render for IconButtonStory {
|
|||
|
||||
let selected_button = StoryItem::new(
|
||||
"Selected",
|
||||
IconButton::new("selected_icon_button", Icon::Hash).selected(true),
|
||||
IconButton::new("selected_icon_button", IconName::Hash).selected(true),
|
||||
)
|
||||
.description("Displays an icon button that is selected.")
|
||||
.usage(
|
||||
|
@ -32,9 +32,9 @@ impl Render for IconButtonStory {
|
|||
|
||||
let selected_with_selected_icon = StoryItem::new(
|
||||
"Selected with `selected_icon`",
|
||||
IconButton::new("selected_with_selected_icon_button", Icon::AudioOn)
|
||||
IconButton::new("selected_with_selected_icon_button", IconName::AudioOn)
|
||||
.selected(true)
|
||||
.selected_icon(Icon::AudioOff),
|
||||
.selected_icon(IconName::AudioOff),
|
||||
)
|
||||
.description(
|
||||
"Displays an icon button that is selected and shows a different icon when selected.",
|
||||
|
@ -49,7 +49,7 @@ impl Render for IconButtonStory {
|
|||
|
||||
let disabled_button = StoryItem::new(
|
||||
"Disabled",
|
||||
IconButton::new("disabled_icon_button", Icon::Hash).disabled(true),
|
||||
IconButton::new("disabled_icon_button", IconName::Hash).disabled(true),
|
||||
)
|
||||
.description("Displays an icon button that is disabled.")
|
||||
.usage(
|
||||
|
@ -60,7 +60,7 @@ impl Render for IconButtonStory {
|
|||
|
||||
let with_on_click_button = StoryItem::new(
|
||||
"With `on_click`",
|
||||
IconButton::new("with_on_click_button", Icon::Ai).on_click(|_event, _cx| {
|
||||
IconButton::new("with_on_click_button", IconName::Ai).on_click(|_event, _cx| {
|
||||
println!("Clicked!");
|
||||
}),
|
||||
)
|
||||
|
@ -75,7 +75,7 @@ impl Render for IconButtonStory {
|
|||
|
||||
let with_tooltip_button = StoryItem::new(
|
||||
"With `tooltip`",
|
||||
IconButton::new("with_tooltip_button", Icon::MessageBubbles)
|
||||
IconButton::new("with_tooltip_button", IconName::MessageBubbles)
|
||||
.tooltip(|cx| Tooltip::text("Open messages", cx)),
|
||||
)
|
||||
.description("Displays an icon button that has a tooltip when hovered.")
|
||||
|
@ -88,7 +88,7 @@ impl Render for IconButtonStory {
|
|||
|
||||
let selected_with_tooltip_button = StoryItem::new(
|
||||
"Selected with `tooltip`",
|
||||
IconButton::new("selected_with_tooltip_button", Icon::InlayHint)
|
||||
IconButton::new("selected_with_tooltip_button", IconName::InlayHint)
|
||||
.selected(true)
|
||||
.tooltip(|cx| Tooltip::text("Toggle inlay hints", cx)),
|
||||
)
|
||||
|
|
|
@ -2,7 +2,7 @@ use gpui::Render;
|
|||
use story::Story;
|
||||
|
||||
use crate::{prelude::*, IconButton};
|
||||
use crate::{Icon, ListHeader};
|
||||
use crate::{IconName, ListHeader};
|
||||
|
||||
pub struct ListHeaderStory;
|
||||
|
||||
|
@ -13,19 +13,19 @@ impl Render for ListHeaderStory {
|
|||
.child(Story::label("Default"))
|
||||
.child(ListHeader::new("Section 1"))
|
||||
.child(Story::label("With left icon"))
|
||||
.child(ListHeader::new("Section 2").start_slot(IconElement::new(Icon::Bell)))
|
||||
.child(ListHeader::new("Section 2").start_slot(Icon::new(IconName::Bell)))
|
||||
.child(Story::label("With left icon and meta"))
|
||||
.child(
|
||||
ListHeader::new("Section 3")
|
||||
.start_slot(IconElement::new(Icon::BellOff))
|
||||
.end_slot(IconButton::new("action_1", Icon::Bolt)),
|
||||
.start_slot(Icon::new(IconName::BellOff))
|
||||
.end_slot(IconButton::new("action_1", IconName::Bolt)),
|
||||
)
|
||||
.child(Story::label("With multiple meta"))
|
||||
.child(
|
||||
ListHeader::new("Section 4")
|
||||
.end_slot(IconButton::new("action_1", Icon::Bolt))
|
||||
.end_slot(IconButton::new("action_2", Icon::ExclamationTriangle))
|
||||
.end_slot(IconButton::new("action_3", Icon::Plus)),
|
||||
.end_slot(IconButton::new("action_1", IconName::Bolt))
|
||||
.end_slot(IconButton::new("action_2", IconName::ExclamationTriangle))
|
||||
.end_slot(IconButton::new("action_3", IconName::Plus)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use gpui::Render;
|
||||
use gpui::{Render, SharedUrl};
|
||||
use story::Story;
|
||||
|
||||
use crate::{prelude::*, Avatar};
|
||||
use crate::{Icon, ListItem};
|
||||
use crate::{IconName, ListItem};
|
||||
|
||||
pub struct ListItemStory;
|
||||
|
||||
|
@ -18,13 +18,13 @@ impl Render for ListItemStory {
|
|||
ListItem::new("inset_list_item")
|
||||
.inset(true)
|
||||
.start_slot(
|
||||
IconElement::new(Icon::Bell)
|
||||
Icon::new(IconName::Bell)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.child("Hello, world!")
|
||||
.end_slot(
|
||||
IconElement::new(Icon::Bell)
|
||||
Icon::new(IconName::Bell)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
),
|
||||
|
@ -34,7 +34,7 @@ impl Render for ListItemStory {
|
|||
ListItem::new("with start slot_icon")
|
||||
.child("Hello, world!")
|
||||
.start_slot(
|
||||
IconElement::new(Icon::Bell)
|
||||
Icon::new(IconName::Bell)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
),
|
||||
|
@ -43,7 +43,7 @@ impl Render for ListItemStory {
|
|||
.child(
|
||||
ListItem::new("with_start slot avatar")
|
||||
.child("Hello, world!")
|
||||
.start_slot(Avatar::new(SharedString::from(
|
||||
.start_slot(Avatar::new(SharedUrl::from(
|
||||
"https://avatars.githubusercontent.com/u/1714999?v=4",
|
||||
))),
|
||||
)
|
||||
|
@ -51,7 +51,7 @@ impl Render for ListItemStory {
|
|||
.child(
|
||||
ListItem::new("with_left_avatar")
|
||||
.child("Hello, world!")
|
||||
.end_slot(Avatar::new(SharedString::from(
|
||||
.end_slot(Avatar::new(SharedUrl::from(
|
||||
"https://avatars.githubusercontent.com/u/1714999?v=4",
|
||||
))),
|
||||
)
|
||||
|
@ -62,23 +62,23 @@ impl Render for ListItemStory {
|
|||
.end_slot(
|
||||
h_stack()
|
||||
.gap_2()
|
||||
.child(Avatar::new(SharedString::from(
|
||||
.child(Avatar::new(SharedUrl::from(
|
||||
"https://avatars.githubusercontent.com/u/1789?v=4",
|
||||
)))
|
||||
.child(Avatar::new(SharedString::from(
|
||||
.child(Avatar::new(SharedUrl::from(
|
||||
"https://avatars.githubusercontent.com/u/1789?v=4",
|
||||
)))
|
||||
.child(Avatar::new(SharedString::from(
|
||||
.child(Avatar::new(SharedUrl::from(
|
||||
"https://avatars.githubusercontent.com/u/1789?v=4",
|
||||
)))
|
||||
.child(Avatar::new(SharedString::from(
|
||||
.child(Avatar::new(SharedUrl::from(
|
||||
"https://avatars.githubusercontent.com/u/1789?v=4",
|
||||
)))
|
||||
.child(Avatar::new(SharedString::from(
|
||||
.child(Avatar::new(SharedUrl::from(
|
||||
"https://avatars.githubusercontent.com/u/1789?v=4",
|
||||
))),
|
||||
)
|
||||
.end_hover_slot(Avatar::new(SharedString::from(
|
||||
.end_hover_slot(Avatar::new(SharedUrl::from(
|
||||
"https://avatars.githubusercontent.com/u/1714999?v=4",
|
||||
))),
|
||||
)
|
||||
|
|
|
@ -27,7 +27,7 @@ impl Render for TabStory {
|
|||
h_stack().child(
|
||||
Tab::new("tab_1")
|
||||
.end_slot(
|
||||
IconButton::new("close_button", Icon::Close)
|
||||
IconButton::new("close_button", IconName::Close)
|
||||
.icon_color(Color::Muted)
|
||||
.size(ButtonSize::None)
|
||||
.icon_size(IconSize::XSmall),
|
||||
|
|
|
@ -38,16 +38,19 @@ impl Render for TabBarStory {
|
|||
h_stack().child(
|
||||
TabBar::new("tab_bar_1")
|
||||
.start_child(
|
||||
IconButton::new("navigate_backward", Icon::ArrowLeft)
|
||||
IconButton::new("navigate_backward", IconName::ArrowLeft)
|
||||
.icon_size(IconSize::Small),
|
||||
)
|
||||
.start_child(
|
||||
IconButton::new("navigate_forward", Icon::ArrowRight)
|
||||
IconButton::new("navigate_forward", IconName::ArrowRight)
|
||||
.icon_size(IconSize::Small),
|
||||
)
|
||||
.end_child(IconButton::new("new", Icon::Plus).icon_size(IconSize::Small))
|
||||
.end_child(
|
||||
IconButton::new("split_pane", Icon::Split).icon_size(IconSize::Small),
|
||||
IconButton::new("new", IconName::Plus).icon_size(IconSize::Small),
|
||||
)
|
||||
.end_child(
|
||||
IconButton::new("split_pane", IconName::Split)
|
||||
.icon_size(IconSize::Small),
|
||||
)
|
||||
.children(tabs),
|
||||
),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/// A trait for elements that can be disabled.
|
||||
/// A trait for elements that can be disabled. Generally used to implement disabling an element's interactivity and changing its appearance to reflect that it is disabled.
|
||||
pub trait Disableable {
|
||||
/// Sets whether the element is disabled.
|
||||
fn disabled(self, disabled: bool) -> Self;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use gpui::DefiniteLength;
|
||||
|
||||
/// A trait for elements that have a fixed with.
|
||||
/// A trait for elements that can have a fixed with. Enables the use of the `width` and `full_width` methods.
|
||||
pub trait FixedWidth {
|
||||
/// Sets the width of the element.
|
||||
fn width(self, width: DefiniteLength) -> Self;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! The prelude of this crate. When building UI in Zed you almost always want to import this.
|
||||
|
||||
pub use gpui::prelude::*;
|
||||
pub use gpui::{
|
||||
div, px, relative, rems, AbsoluteLength, DefiniteLength, Div, Element, ElementId,
|
||||
|
@ -14,6 +16,7 @@ pub use crate::visible_on_hover::*;
|
|||
pub use crate::{h_stack, v_stack};
|
||||
pub use crate::{Button, ButtonSize, ButtonStyle, IconButton, SelectableButton};
|
||||
pub use crate::{ButtonCommon, Color, StyledExt};
|
||||
pub use crate::{Icon, IconElement, IconPosition, IconSize};
|
||||
pub use crate::{Headline, HeadlineSize};
|
||||
pub use crate::{Icon, IconName, IconPosition, IconSize};
|
||||
pub use crate::{Label, LabelCommon, LabelSize, LineHeightStyle};
|
||||
pub use theme::ActiveTheme;
|
||||
|
|
|
@ -1,18 +1,27 @@
|
|||
/// A trait for elements that can be selected.
|
||||
///
|
||||
/// Generally used to enable "toggle" or "active" behavior and styles on an element through the [`Selection`] status.
|
||||
pub trait Selectable {
|
||||
/// Sets whether the element is selected.
|
||||
fn selected(self, selected: bool) -> Self;
|
||||
}
|
||||
|
||||
/// Represents the selection status of an element.
|
||||
#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub enum Selection {
|
||||
/// The element is not selected.
|
||||
#[default]
|
||||
Unselected,
|
||||
/// The selection state of the element is indeterminate.
|
||||
Indeterminate,
|
||||
/// The element is selected.
|
||||
Selected,
|
||||
}
|
||||
|
||||
impl Selection {
|
||||
/// Returns the inverse of the current selection status.
|
||||
///
|
||||
/// Indeterminate states become selected if inverted.
|
||||
pub fn inverse(&self) -> Self {
|
||||
match self {
|
||||
Self::Unselected | Self::Indeterminate => Self::Selected,
|
||||
|
|
|
@ -14,7 +14,7 @@ fn elevated<E: Styled>(this: E, cx: &mut WindowContext, index: ElevationIndex) -
|
|||
.shadow(index.shadow())
|
||||
}
|
||||
|
||||
/// Extends [`Styled`](gpui::Styled) with Zed specific styling methods.
|
||||
/// Extends [`gpui::Styled`] with Zed-specific styling methods.
|
||||
pub trait StyledExt: Styled + Sized {
|
||||
/// Horizontally stacks elements.
|
||||
///
|
||||
|
@ -30,6 +30,7 @@ pub trait StyledExt: Styled + Sized {
|
|||
self.flex().flex_col()
|
||||
}
|
||||
|
||||
/// Sets the text size using a [`UiTextSize`].
|
||||
fn text_ui_size(self, size: UiTextSize) -> Self {
|
||||
self.text_size(size.rems())
|
||||
}
|
||||
|
@ -40,7 +41,7 @@ pub trait StyledExt: Styled + Sized {
|
|||
///
|
||||
/// Note: The absolute size of this text will change based on a user's `ui_scale` setting.
|
||||
///
|
||||
/// Use [`text_ui_sm`] for regular-sized text.
|
||||
/// Use `text_ui_sm` for smaller text.
|
||||
fn text_ui(self) -> Self {
|
||||
self.text_size(UiTextSize::default().rems())
|
||||
}
|
||||
|
@ -51,7 +52,7 @@ pub trait StyledExt: Styled + Sized {
|
|||
///
|
||||
/// Note: The absolute size of this text will change based on a user's `ui_scale` setting.
|
||||
///
|
||||
/// Use [`text_ui`] for regular-sized text.
|
||||
/// Use `text_ui` for regular-sized text.
|
||||
fn text_ui_sm(self) -> Self {
|
||||
self.text_size(UiTextSize::Small.rems())
|
||||
}
|
||||
|
@ -62,7 +63,7 @@ pub trait StyledExt: Styled + Sized {
|
|||
///
|
||||
/// Note: The absolute size of this text will change based on a user's `ui_scale` setting.
|
||||
///
|
||||
/// Use [`text_ui`] for regular-sized text.
|
||||
/// Use `text_ui` for regular-sized text.
|
||||
fn text_ui_xs(self) -> Self {
|
||||
self.text_size(UiTextSize::XSmall.rems())
|
||||
}
|
||||
|
@ -78,7 +79,7 @@ pub trait StyledExt: Styled + Sized {
|
|||
self.text_size(settings.buffer_font_size(cx))
|
||||
}
|
||||
|
||||
/// The [`Surface`](ui::ElevationIndex::Surface) elevation level, located above the app background, is the standard level for all elements
|
||||
/// The [`Surface`](ElevationIndex::Surface) elevation level, located above the app background, is the standard level for all elements
|
||||
///
|
||||
/// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()`
|
||||
///
|
||||
|
@ -87,7 +88,7 @@ pub trait StyledExt: Styled + Sized {
|
|||
elevated(self, cx, ElevationIndex::Surface)
|
||||
}
|
||||
|
||||
/// Non-Modal Elevated Surfaces appear above the [`Surface`](ui::ElevationIndex::Surface) layer and is used for things that should appear above most UI elements like an editor or panel, but not elements like popovers, context menus, modals, etc.
|
||||
/// Non-Modal Elevated Surfaces appear above the [`Surface`](ElevationIndex::Surface) layer and is used for things that should appear above most UI elements like an editor or panel, but not elements like popovers, context menus, modals, etc.
|
||||
///
|
||||
/// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()`
|
||||
///
|
||||
|
@ -100,7 +101,7 @@ pub trait StyledExt: Styled + Sized {
|
|||
///
|
||||
/// Elements rendered at this layer should have an enforced behavior: Any interaction outside of the modal will either dismiss the modal or prompt an action (Save your progress, etc) then dismiss the modal.
|
||||
///
|
||||
/// If the element does not have this behavior, it should be rendered at the [`Elevated Surface`](ui::ElevationIndex::ElevatedSurface) layer.
|
||||
/// If the element does not have this behavior, it should be rendered at the [`Elevated Surface`](ElevationIndex::ElevatedSurface) layer.
|
||||
///
|
||||
/// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()`
|
||||
///
|
||||
|
@ -119,26 +120,32 @@ pub trait StyledExt: Styled + Sized {
|
|||
self.border_color(cx.theme().colors().border_variant)
|
||||
}
|
||||
|
||||
/// Sets the background color to red for debugging when building UI.
|
||||
fn debug_bg_red(self) -> Self {
|
||||
self.bg(hsla(0. / 360., 1., 0.5, 1.))
|
||||
}
|
||||
|
||||
/// Sets the background color to green for debugging when building UI.
|
||||
fn debug_bg_green(self) -> Self {
|
||||
self.bg(hsla(120. / 360., 1., 0.5, 1.))
|
||||
}
|
||||
|
||||
/// Sets the background color to blue for debugging when building UI.
|
||||
fn debug_bg_blue(self) -> Self {
|
||||
self.bg(hsla(240. / 360., 1., 0.5, 1.))
|
||||
}
|
||||
|
||||
/// Sets the background color to yellow for debugging when building UI.
|
||||
fn debug_bg_yellow(self) -> Self {
|
||||
self.bg(hsla(60. / 360., 1., 0.5, 1.))
|
||||
}
|
||||
|
||||
/// Sets the background color to cyan for debugging when building UI.
|
||||
fn debug_bg_cyan(self) -> Self {
|
||||
self.bg(hsla(160. / 360., 1., 0.5, 1.))
|
||||
}
|
||||
|
||||
/// Sets the background color to magenta for debugging when building UI.
|
||||
fn debug_bg_magenta(self) -> Self {
|
||||
self.bg(hsla(300. / 360., 1., 0.5, 1.))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use gpui::{Hsla, WindowContext};
|
||||
use theme::ActiveTheme;
|
||||
|
||||
/// Sets a color that has a consistent meaning across all themes.
|
||||
#[derive(Debug, Default, PartialEq, Copy, Clone)]
|
||||
pub enum Color {
|
||||
#[default]
|
||||
|
|
|
@ -85,6 +85,7 @@ impl LayerIndex {
|
|||
}
|
||||
}
|
||||
|
||||
/// An appropriate z-index for the given layer based on its intended useage.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ElementIndex {
|
||||
Effect,
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
use gpui::{rems, Rems};
|
||||
use gpui::{
|
||||
div, rems, IntoElement, ParentElement, Rems, RenderOnce, SharedString, Styled, WindowContext,
|
||||
};
|
||||
use settings::Settings;
|
||||
use theme::{ActiveTheme, ThemeSettings};
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub enum UiTextSize {
|
||||
|
@ -33,3 +37,70 @@ impl UiTextSize {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The size of a [`Headline`] element
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
|
||||
pub enum HeadlineSize {
|
||||
XSmall,
|
||||
Small,
|
||||
#[default]
|
||||
Medium,
|
||||
Large,
|
||||
XLarge,
|
||||
}
|
||||
|
||||
impl HeadlineSize {
|
||||
pub fn size(self) -> Rems {
|
||||
match self {
|
||||
// Based on the Major Second scale
|
||||
Self::XSmall => rems(0.88),
|
||||
Self::Small => rems(1.0),
|
||||
Self::Medium => rems(1.125),
|
||||
Self::Large => rems(1.27),
|
||||
Self::XLarge => rems(1.43),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn line_height(self) -> Rems {
|
||||
match self {
|
||||
Self::XSmall => rems(1.6),
|
||||
Self::Small => rems(1.6),
|
||||
Self::Medium => rems(1.6),
|
||||
Self::Large => rems(1.6),
|
||||
Self::XLarge => rems(1.6),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct Headline {
|
||||
size: HeadlineSize,
|
||||
text: SharedString,
|
||||
}
|
||||
|
||||
impl RenderOnce for Headline {
|
||||
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
||||
let ui_font = ThemeSettings::get_global(cx).ui_font.family.clone();
|
||||
|
||||
div()
|
||||
.font(ui_font)
|
||||
.line_height(self.size.line_height())
|
||||
.text_size(self.size.size())
|
||||
.text_color(cx.theme().colors().text)
|
||||
.child(self.text)
|
||||
}
|
||||
}
|
||||
|
||||
impl Headline {
|
||||
pub fn new(text: impl Into<SharedString>) -> Self {
|
||||
Self {
|
||||
size: HeadlineSize::default(),
|
||||
text: text.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(mut self, size: HeadlineSize) -> Self {
|
||||
self.size = size;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
//! This crate provides a set of UI primitives and components that are used to build all of the elements in Zed's UI.
|
||||
//!
|
||||
|
||||
#![doc = include_str!("../docs/building-ui.md")]
|
||||
|
||||
mod clickable;
|
||||
mod components;
|
||||
mod disableable;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! UI-related utilities (e.g. converting dates to a human-readable form).
|
||||
|
||||
mod format_distance;
|
||||
|
||||
pub use format_distance::*;
|
||||
|
|
|
@ -7,10 +7,10 @@ pub enum DateTimeType {
|
|||
}
|
||||
|
||||
impl DateTimeType {
|
||||
/// Converts the DateTimeType to a NaiveDateTime.
|
||||
/// Converts the [`DateTimeType`] to a [`NaiveDateTime`].
|
||||
///
|
||||
/// If the DateTimeType is already a NaiveDateTime, it will be returned as is.
|
||||
/// If the DateTimeType is a DateTime<Local>, it will be converted to a NaiveDateTime.
|
||||
/// If the [`DateTimeType`] is already a [`NaiveDateTime`], it will be returned as is.
|
||||
/// If the [`DateTimeType`] is a [`DateTime<Local>`], it will be converted to a [`NaiveDateTime`].
|
||||
pub fn to_naive(&self) -> NaiveDateTime {
|
||||
match self {
|
||||
DateTimeType::Naive(naive) => *naive,
|
||||
|
@ -68,13 +68,13 @@ impl FormatDistance {
|
|||
}
|
||||
}
|
||||
|
||||
/// Calculates the distance in seconds between two NaiveDateTime objects.
|
||||
/// Calculates the distance in seconds between two [`NaiveDateTime`] objects.
|
||||
/// It returns a signed integer denoting the difference. If `date` is earlier than `base_date`, the returned value will be negative.
|
||||
///
|
||||
/// ## Arguments
|
||||
///
|
||||
/// * `date` - A NaiveDateTime object representing the date of interest
|
||||
/// * `base_date` - A NaiveDateTime object representing the base date against which the comparison is made
|
||||
/// * `date` - A [NaiveDateTime`] object representing the date of interest
|
||||
/// * `base_date` - A [NaiveDateTime`] object representing the base date against which the comparison is made
|
||||
fn distance_in_seconds(date: NaiveDateTime, base_date: NaiveDateTime) -> i64 {
|
||||
let duration = date.signed_duration_since(base_date);
|
||||
-duration.num_seconds()
|
||||
|
@ -233,29 +233,7 @@ fn distance_string(
|
|||
///
|
||||
/// For example, "less than a minute ago", "about 2 hours ago", "3 months from now", etc.
|
||||
///
|
||||
/// Use [naive_format_distance_from_now] to compare a NaiveDateTime against now.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `date` - The NaiveDateTime to compare.
|
||||
/// * `base_date` - The NaiveDateTime to compare against.
|
||||
/// * `include_seconds` - A boolean. If true, distances less than a minute are more detailed
|
||||
/// * `add_suffix` - A boolean. If true, result indicates if the time is in the past or future
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use chrono::DateTime;
|
||||
/// use ui::utils::format_distance;
|
||||
///
|
||||
/// fn time_between_moon_landings() -> String {
|
||||
/// let date = DateTime::parse_from_rfc3339("1969-07-20T00:00:00Z").unwrap().naive_local();
|
||||
/// let base_date = DateTime::parse_from_rfc3339("1972-12-14T00:00:00Z").unwrap().naive_local();
|
||||
/// format!("There was {} between the first and last crewed moon landings.", naive_format_distance(date, base_date, false, false))
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Output: `"There was about 3 years between the first and last crewed moon landings."`
|
||||
/// Use [`format_distance_from_now`] to compare a NaiveDateTime against now.
|
||||
pub fn format_distance(
|
||||
date: DateTimeType,
|
||||
base_date: NaiveDateTime,
|
||||
|
@ -271,26 +249,6 @@ pub fn format_distance(
|
|||
/// Get the time difference between a date and now as relative human readable string.
|
||||
///
|
||||
/// For example, "less than a minute ago", "about 2 hours ago", "3 months from now", etc.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `datetime` - The NaiveDateTime to compare with the current time.
|
||||
/// * `include_seconds` - A boolean. If true, distances less than a minute are more detailed
|
||||
/// * `add_suffix` - A boolean. If true, result indicates if the time is in the past or future
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use chrono::DateTime;
|
||||
/// use ui::utils::naive_format_distance_from_now;
|
||||
///
|
||||
/// fn time_since_first_moon_landing() -> String {
|
||||
/// let date = DateTime::parse_from_rfc3339("1969-07-20T00:00:00Z").unwrap().naive_local();
|
||||
/// format!("It's been {} since Apollo 11 first landed on the moon.", naive_format_distance_from_now(date, false, false))
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Output: `It's been over 54 years since Apollo 11 first landed on the moon.`
|
||||
pub fn format_distance_from_now(
|
||||
datetime: DateTimeType,
|
||||
include_seconds: bool,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue