diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index 15f9e5c59dfef9c1ba678eb159158d1c3fab4aed..20e6347d01c3d9401bb642ccebb4fe7092ca30dd 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -77,7 +77,7 @@ use ui::TintColor; use ui::{ prelude::*, utils::{format_distance_from_now, DateTimeType}, - Avatar, AvatarShape, ButtonLike, ContextMenu, Disclosure, ElevationIndex, KeyBinding, ListItem, + Avatar, ButtonLike, ContextMenu, Disclosure, ElevationIndex, KeyBinding, ListItem, ListItemSpacing, PopoverMenu, PopoverMenuHandle, Tooltip, }; use util::{maybe, ResultExt}; @@ -262,9 +262,7 @@ impl PickerDelegate for SavedContextPickerDelegate { .gap_2() .children(if let Some(host_user) = host_user { vec![ - Avatar::new(host_user.avatar_uri.clone()) - .shape(AvatarShape::Circle) - .into_any_element(), + Avatar::new(host_user.avatar_uri.clone()).into_any_element(), Label::new(format!("Shared by @{}", host_user.github_login)) .color(Color::Muted) .size(LabelSize::Small) diff --git a/crates/assistant/src/prompt_library.rs b/crates/assistant/src/prompt_library.rs index 24e20a18a799a690721d3efca15ac6aa684bb950..6c43579d6ebd02a70403f5b61bdd96be0141b203 100644 --- a/crates/assistant/src/prompt_library.rs +++ b/crates/assistant/src/prompt_library.rs @@ -910,7 +910,7 @@ impl PromptLibrary { .features .clone(), font_size: HeadlineSize::Large - .size() + .rems() .into(), font_weight: settings.ui_font.weight, line_height: relative( diff --git a/crates/storybook/src/stories/with_rem_size.rs b/crates/storybook/src/stories/with_rem_size.rs index 11add24955bad3ca03a29a91b8a8ce73ea54813c..558dab6c547784401af62290550a0bfe06b8265d 100644 --- a/crates/storybook/src/stories/with_rem_size.rs +++ b/crates/storybook/src/stories/with_rem_size.rs @@ -1,7 +1,7 @@ use gpui::{AnyElement, Hsla, Render}; use story::Story; -use ui::{prelude::*, WithRemSize}; +use ui::{prelude::*, utils::WithRemSize}; pub struct WithRemSizeStory; diff --git a/crates/ui/src/components/avatar/avatar.rs b/crates/ui/src/components/avatar/avatar.rs index 27cf86a01fb01408bf41c7b379aa8571d3bd9b90..4106b17452fd2582e605d6a1ceee22ed1c61311e 100644 --- a/crates/ui/src/components/avatar/avatar.rs +++ b/crates/ui/src/components/avatar/avatar.rs @@ -2,16 +2,6 @@ use crate::prelude::*; use gpui::{img, AnyElement, Hsla, ImageSource, Img, IntoElement, Styled}; -/// The shape of an [`Avatar`]. -#[derive(Debug, Default, PartialEq, Clone)] -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 @@ -20,7 +10,6 @@ pub enum AvatarShape { /// use ui::{Avatar, AvatarShape}; /// /// Avatar::new("path/to/image.png") -/// .shape(AvatarShape::Circle) /// .grayscale(true) /// .border_color(gpui::red()); /// ``` @@ -33,6 +22,7 @@ pub struct Avatar { } impl Avatar { + /// Creates a new avatar element with the specified image source. pub fn new(src: impl Into) -> Self { Avatar { image: img(src), @@ -42,26 +32,6 @@ impl Avatar { } } - /// Sets the shape of the avatar image. - /// - /// This method allows the shape of the avatar to be specified using an [`AvatarShape`]. - /// 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 { - AvatarShape::Circle => self.image.rounded_full(), - AvatarShape::RoundedRectangle => self.image.rounded_md(), - }; - self - } - /// Applies a grayscale filter to the avatar image. /// /// # Examples @@ -76,6 +46,11 @@ impl Avatar { self } + /// Sets the border color of the avatar. + /// + /// This might be used to match the border to the background color of + /// the parent element to create the illusion of cropping another + /// shape underneath (for example in face piles.) pub fn border_color(mut self, color: impl Into) -> Self { self.border_color = Some(color.into()); self @@ -87,6 +62,7 @@ impl Avatar { self } + /// Sets the current indicator to be displayed on the avatar, if any. pub fn indicator(mut self, indicator: impl Into>) -> Self { self.indicator = indicator.into().map(IntoElement::into_any_element); self @@ -95,10 +71,6 @@ impl 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(AvatarShape::Circle); - } - let border_width = if self.border_color.is_some() { px(2.) } else { diff --git a/crates/ui/src/components/avatar/avatar_audio_status_indicator.rs b/crates/ui/src/components/avatar/avatar_audio_status_indicator.rs index e249727a0ce2115eff674a3ecf4192d4c9679ea6..8ff6491db7b01b10ae0911c786312adc5b1a77c9 100644 --- a/crates/ui/src/components/avatar/avatar_audio_status_indicator.rs +++ b/crates/ui/src/components/avatar/avatar_audio_status_indicator.rs @@ -2,12 +2,17 @@ use gpui::AnyView; use crate::prelude::*; +/// The audio status of an player, for use in representing +/// their status visually on their avatar. #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] pub enum AudioStatus { + /// The player's microphone is muted. Muted, + /// The player's microphone is muted, and collaboration audio is disabled. Deafened, } +/// An indicator that shows the audio status of a player. #[derive(IntoElement)] pub struct AvatarAudioStatusIndicator { audio_status: AudioStatus, @@ -15,6 +20,7 @@ pub struct AvatarAudioStatusIndicator { } impl AvatarAudioStatusIndicator { + /// Creates a new `AvatarAudioStatusIndicator` pub fn new(audio_status: AudioStatus) -> Self { Self { audio_status, @@ -22,6 +28,7 @@ impl AvatarAudioStatusIndicator { } } + /// Sets the tooltip for the indicator. pub fn tooltip(mut self, tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self { self.tooltip = Some(Box::new(tooltip)); self diff --git a/crates/ui/src/components/avatar/avatar_availability_indicator.rs b/crates/ui/src/components/avatar/avatar_availability_indicator.rs index 3e4f9b2d1bc7d00a3383b6b1ebe1bf11ec2195a1..4690f8fccddba2caa6ee22943994c916047f10f4 100644 --- a/crates/ui/src/components/avatar/avatar_availability_indicator.rs +++ b/crates/ui/src/components/avatar/avatar_availability_indicator.rs @@ -1,3 +1,4 @@ +#![allow(missing_docs)] use crate::prelude::*; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] diff --git a/crates/ui/src/components/button/button.rs b/crates/ui/src/components/button/button.rs index 1e11d25cc6618e273c941df6b2bc7a05bd46e645..f81de83a2bf7c485dcd172d9f92904d6e11ff533 100644 --- a/crates/ui/src/components/button/button.rs +++ b/crates/ui/src/components/button/button.rs @@ -1,3 +1,4 @@ +#![allow(missing_docs)] use gpui::{AnyView, DefiniteLength}; use crate::{prelude::*, ElevationIndex, IconPosition, KeyBinding, Spacing}; diff --git a/crates/ui/src/components/button/button_icon.rs b/crates/ui/src/components/button/button_icon.rs index 54ca0f79218eaa6ee1942c081a90566d49ab54e1..f3aebe7f765ffafb736f90b684c7d91f435e9d1e 100644 --- a/crates/ui/src/components/button/button_icon.rs +++ b/crates/ui/src/components/button/button_icon.rs @@ -1,3 +1,4 @@ +#![allow(missing_docs)] use crate::{prelude::*, Icon, IconName, IconSize}; /// An icon that appears within a button. diff --git a/crates/ui/src/components/button/button_like.rs b/crates/ui/src/components/button/button_like.rs index a22c27d24176d073d703c79ffcb1c8c772f68b96..22e84213913188a51c08de8571ce15c7f67355e6 100644 --- a/crates/ui/src/components/button/button_like.rs +++ b/crates/ui/src/components/button/button_like.rs @@ -1,8 +1,9 @@ +#![allow(missing_docs)] use gpui::{relative, CursorStyle, DefiniteLength, MouseButton}; use gpui::{transparent_black, AnyElement, AnyView, ClickEvent, Hsla, Rems}; use smallvec::SmallVec; -use crate::{prelude::*, Elevation, ElevationIndex, Spacing}; +use crate::{prelude::*, ElevationIndex, Spacing}; /// A trait for buttons that can be Selected. Enables setting the [`ButtonStyle`] of a button when it is selected. pub trait SelectableButton: Selectable { @@ -145,20 +146,12 @@ pub(crate) struct ButtonLikeStyles { pub icon_color: Hsla, } -fn element_bg_from_elevation(elevation: Option, cx: &mut WindowContext) -> Hsla { +fn element_bg_from_elevation(elevation: Option, cx: &mut WindowContext) -> Hsla { match elevation { - Some(Elevation::ElevationIndex(ElevationIndex::Background)) => { - cx.theme().colors().element_background - } - Some(Elevation::ElevationIndex(ElevationIndex::ElevatedSurface)) => { - cx.theme().colors().surface_background - } - Some(Elevation::ElevationIndex(ElevationIndex::Surface)) => { - cx.theme().colors().elevated_surface_background - } - Some(Elevation::ElevationIndex(ElevationIndex::ModalSurface)) => { - cx.theme().colors().background - } + Some(ElevationIndex::Background) => cx.theme().colors().element_background, + Some(ElevationIndex::ElevatedSurface) => cx.theme().colors().surface_background, + Some(ElevationIndex::Surface) => cx.theme().colors().elevated_surface_background, + Some(ElevationIndex::ModalSurface) => cx.theme().colors().background, _ => cx.theme().colors().element_background, } } @@ -166,7 +159,7 @@ fn element_bg_from_elevation(elevation: Option, cx: &mut WindowContex impl ButtonStyle { pub(crate) fn enabled( self, - elevation: Option, + elevation: Option, cx: &mut WindowContext, ) -> ButtonLikeStyles { let filled_background = element_bg_from_elevation(elevation, cx); @@ -196,7 +189,7 @@ impl ButtonStyle { pub(crate) fn hovered( self, - elevation: Option, + elevation: Option, cx: &mut WindowContext, ) -> ButtonLikeStyles { let mut filled_background = element_bg_from_elevation(elevation, cx); @@ -281,7 +274,7 @@ impl ButtonStyle { #[allow(unused)] pub(crate) fn disabled( self, - elevation: Option, + elevation: Option, cx: &mut WindowContext, ) -> ButtonLikeStyles { element_bg_from_elevation(elevation, cx).fade_out(0.82); @@ -348,7 +341,7 @@ pub struct ButtonLike { pub(super) selected_style: Option, pub(super) width: Option, pub(super) height: Option, - pub(super) layer: Option, + pub(super) layer: Option, size: ButtonSize, rounding: Option, tooltip: Option AnyView>>, @@ -463,7 +456,7 @@ impl ButtonCommon for ButtonLike { } fn layer(mut self, elevation: ElevationIndex) -> Self { - self.layer = Some(elevation.into()); + self.layer = Some(elevation); self } } diff --git a/crates/ui/src/components/button/icon_button.rs b/crates/ui/src/components/button/icon_button.rs index cf564efabb3817043ebc03587aead7c195b1dac0..bad10d6fb43b8d08d8b3e468cc95f84921454a76 100644 --- a/crates/ui/src/components/button/icon_button.rs +++ b/crates/ui/src/components/button/icon_button.rs @@ -1,3 +1,4 @@ +#![allow(missing_docs)] use gpui::{AnyView, DefiniteLength}; use super::button_like::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle}; diff --git a/crates/ui/src/components/button/toggle_button.rs b/crates/ui/src/components/button/toggle_button.rs index 3ad47ed166d6e43432f0fd8f01db84c594f0e97b..33577fc4e8c169ef96248cee882bc0de248a0f5b 100644 --- a/crates/ui/src/components/button/toggle_button.rs +++ b/crates/ui/src/components/button/toggle_button.rs @@ -1,3 +1,4 @@ +#![allow(missing_docs)] use gpui::{AnyView, ClickEvent}; use crate::{prelude::*, ButtonLike, ButtonLikeRounding, ElevationIndex}; diff --git a/crates/ui/src/components/checkbox.rs b/crates/ui/src/components/checkbox.rs index d750d6c0364645336ecd8ba70a4d674880e5daa0..d3c4d377ae26e4245d39fcdae53f18f2728a755c 100644 --- a/crates/ui/src/components/checkbox.rs +++ b/crates/ui/src/components/checkbox.rs @@ -1,3 +1,4 @@ +#![allow(missing_docs)] mod checkbox_with_label; pub use checkbox_with_label::*; diff --git a/crates/ui/src/components/checkbox/checkbox.rs b/crates/ui/src/components/checkbox/checkbox.rs index cd1ea97ea9d1ea455382183a093954f1dc8bfbf8..472bfb23f1091dde08f26eac33e5b39c10dbbc63 100644 --- a/crates/ui/src/components/checkbox/checkbox.rs +++ b/crates/ui/src/components/checkbox/checkbox.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use gpui::{div, prelude::*, ElementId, IntoElement, Styled, WindowContext}; use crate::prelude::*; diff --git a/crates/ui/src/components/checkbox/checkbox_with_label.rs b/crates/ui/src/components/checkbox/checkbox_with_label.rs index 2cf8fc28323b30e18c7a3c8b684979d8c94fbcc4..2b92e479389fc8a14cecd9a636dfd87240f266ef 100644 --- a/crates/ui/src/components/checkbox/checkbox_with_label.rs +++ b/crates/ui/src/components/checkbox/checkbox_with_label.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use std::sync::Arc; use crate::{prelude::*, Checkbox}; diff --git a/crates/ui/src/components/context_menu.rs b/crates/ui/src/components/context_menu.rs index 644cb1dd24a9f9fa46965b0b08cf9b43ac229776..92884b0182e660c53857f4367c26a830acf48013 100644 --- a/crates/ui/src/components/context_menu.rs +++ b/crates/ui/src/components/context_menu.rs @@ -1,6 +1,7 @@ +#![allow(missing_docs)] use crate::{ - h_flex, prelude::*, v_flex, Icon, IconName, KeyBinding, Label, List, ListItem, ListSeparator, - ListSubHeader, WithRemSize, + h_flex, prelude::*, utils::WithRemSize, v_flex, Icon, IconName, KeyBinding, Label, List, + ListItem, ListSeparator, ListSubHeader, }; use gpui::{ px, Action, AnyElement, AppContext, DismissEvent, EventEmitter, FocusHandle, FocusableView, diff --git a/crates/ui/src/components/disclosure.rs b/crates/ui/src/components/disclosure.rs index 41ff0a4c3aca61d3be463eaf5cd42c9e12223eaf..9e8ab48221e17f16868bde57b354942a1a077dac 100644 --- a/crates/ui/src/components/disclosure.rs +++ b/crates/ui/src/components/disclosure.rs @@ -1,3 +1,4 @@ +#![allow(missing_docs)] use std::sync::Arc; use gpui::{ClickEvent, CursorStyle}; diff --git a/crates/ui/src/components/divider.rs b/crates/ui/src/components/divider.rs index 772fc1a81a34b816649efeae19d36fc7405c66b2..71234057b22910e6743ebe76ab5a238a71ac65dc 100644 --- a/crates/ui/src/components/divider.rs +++ b/crates/ui/src/components/divider.rs @@ -1,3 +1,4 @@ +#![allow(missing_docs)] use gpui::{Hsla, IntoElement}; use crate::prelude::*; diff --git a/crates/ui/src/components/dropdown_menu.rs b/crates/ui/src/components/dropdown_menu.rs index ab2f6a372ee91dd4a247884cca45747176806377..8d930a63acd479359a2c13912506e2ce7bcb5456 100644 --- a/crates/ui/src/components/dropdown_menu.rs +++ b/crates/ui/src/components/dropdown_menu.rs @@ -1,3 +1,4 @@ +#![allow(missing_docs)] use gpui::{AnchorCorner, ClickEvent, CursorStyle, MouseButton, View}; use crate::{prelude::*, ContextMenu, PopoverMenu}; diff --git a/crates/ui/src/components/facepile.rs b/crates/ui/src/components/facepile.rs index f391fc60bb0caab819d6877f8d6c6a00513b0a3a..c3a56d8e20fe8850657cbe51e2a966872100e8b0 100644 --- a/crates/ui/src/components/facepile.rs +++ b/crates/ui/src/components/facepile.rs @@ -1,3 +1,4 @@ +#![allow(missing_docs)] use crate::prelude::*; use gpui::{AnyElement, StyleRefinement}; use smallvec::SmallVec; diff --git a/crates/ui/src/components/icon.rs b/crates/ui/src/components/icon.rs index 323181e84156f4bab6b62b16b905abccc02ba2d1..693caaaafdacc7c23ed90b79e78d30c9a5f4bfbd 100644 --- a/crates/ui/src/components/icon.rs +++ b/crates/ui/src/components/icon.rs @@ -1,3 +1,4 @@ +#![allow(missing_docs)] use gpui::{svg, AnimationElement, Hsla, IntoElement, Rems, Transformation}; use serde::{Deserialize, Serialize}; use strum::{EnumIter, EnumString, IntoStaticStr}; diff --git a/crates/ui/src/components/image.rs b/crates/ui/src/components/image.rs index e7eefe5fea31008a03b57f6e3139795b131c89aa..a510b4d7a22492b79a2379778dc8ccd771007949 100644 --- a/crates/ui/src/components/image.rs +++ b/crates/ui/src/components/image.rs @@ -1,3 +1,4 @@ +#![allow(missing_docs)] use gpui::{svg, IntoElement, Rems, RenderOnce, Size, Styled, WindowContext}; use serde::{Deserialize, Serialize}; use strum::{EnumIter, EnumString, IntoStaticStr}; diff --git a/crates/ui/src/components/indicator.rs b/crates/ui/src/components/indicator.rs index 0b4a3147c175dba5dc9b56f235467128a1ca6767..009fe44dfef087c4285ec055fd875523204efc0a 100644 --- a/crates/ui/src/components/indicator.rs +++ b/crates/ui/src/components/indicator.rs @@ -1,3 +1,4 @@ +#![allow(missing_docs)] use crate::{prelude::*, AnyIcon}; #[derive(Default)] diff --git a/crates/ui/src/components/keybinding.rs b/crates/ui/src/components/keybinding.rs index 1e4983f5adb808688c8eb15c6c31343e0dfcfa5c..135599b914bc03b8be0698d9f069e1eb5d0dfb18 100644 --- a/crates/ui/src/components/keybinding.rs +++ b/crates/ui/src/components/keybinding.rs @@ -1,5 +1,7 @@ +#![allow(missing_docs)] +use crate::PlatformStyle; use crate::{h_flex, prelude::*, Icon, IconName, IconSize}; -use gpui::{relative, Action, FocusHandle, IntoElement, Keystroke}; +use gpui::{relative, Action, FocusHandle, IntoElement, Keystroke, WindowContext}; #[derive(IntoElement, Clone)] pub struct KeyBinding { @@ -192,3 +194,173 @@ impl KeyIcon { Self { icon } } } + +/// Returns a textual representation of the key binding for the given [`Action`]. +pub fn text_for_action(action: &dyn Action, cx: &mut WindowContext) -> Option { + let key_binding = cx.bindings_for_action(action).last().cloned()?; + Some(text_for_key_binding(key_binding, PlatformStyle::platform())) +} + +/// Returns a textual representation of the key binding for the given [`Action`] +/// as if the provided [`FocusHandle`] was focused. +pub fn text_for_action_in( + action: &dyn Action, + focus: &FocusHandle, + cx: &mut WindowContext, +) -> Option { + let key_binding = cx.bindings_for_action_in(action, focus).last().cloned()?; + Some(text_for_key_binding(key_binding, PlatformStyle::platform())) +} + +/// Returns a textual representation of the given key binding for the specified platform. +pub fn text_for_key_binding( + key_binding: gpui::KeyBinding, + platform_style: PlatformStyle, +) -> String { + key_binding + .keystrokes() + .iter() + .map(|keystroke| text_for_keystroke(keystroke, platform_style)) + .collect::>() + .join(" ") +} + +/// Returns a textual representation of the given [`Keystroke`]. +pub fn text_for_keystroke(keystroke: &Keystroke, platform_style: PlatformStyle) -> String { + let mut text = String::new(); + + let delimiter = match platform_style { + PlatformStyle::Mac => '-', + PlatformStyle::Linux | PlatformStyle::Windows => '+', + }; + + if keystroke.modifiers.function { + match platform_style { + PlatformStyle::Mac => text.push_str("fn"), + PlatformStyle::Linux | PlatformStyle::Windows => text.push_str("Fn"), + } + + text.push(delimiter); + } + + if keystroke.modifiers.control { + match platform_style { + PlatformStyle::Mac => text.push_str("Control"), + PlatformStyle::Linux | PlatformStyle::Windows => text.push_str("Ctrl"), + } + + text.push(delimiter); + } + + if keystroke.modifiers.alt { + match platform_style { + PlatformStyle::Mac => text.push_str("Option"), + PlatformStyle::Linux | PlatformStyle::Windows => text.push_str("Alt"), + } + + text.push(delimiter); + } + + if keystroke.modifiers.platform { + match platform_style { + PlatformStyle::Mac => text.push_str("Command"), + PlatformStyle::Linux => text.push_str("Super"), + PlatformStyle::Windows => text.push_str("Win"), + } + + text.push(delimiter); + } + + if keystroke.modifiers.shift { + match platform_style { + PlatformStyle::Mac | PlatformStyle::Linux | PlatformStyle::Windows => { + text.push_str("Shift") + } + } + + text.push(delimiter); + } + + fn capitalize(str: &str) -> String { + let mut chars = str.chars(); + match chars.next() { + None => String::new(), + Some(first_char) => first_char.to_uppercase().collect::() + chars.as_str(), + } + } + + let key = match keystroke.key.as_str() { + "pageup" => "PageUp", + "pagedown" => "PageDown", + key => &capitalize(key), + }; + + text.push_str(key); + + text +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_text_for_keystroke() { + assert_eq!( + text_for_keystroke(&Keystroke::parse("cmd-c").unwrap(), PlatformStyle::Mac), + "Command-C".to_string() + ); + assert_eq!( + text_for_keystroke(&Keystroke::parse("cmd-c").unwrap(), PlatformStyle::Linux), + "Super+C".to_string() + ); + assert_eq!( + text_for_keystroke(&Keystroke::parse("cmd-c").unwrap(), PlatformStyle::Windows), + "Win+C".to_string() + ); + + assert_eq!( + text_for_keystroke( + &Keystroke::parse("ctrl-alt-delete").unwrap(), + PlatformStyle::Mac + ), + "Control-Option-Delete".to_string() + ); + assert_eq!( + text_for_keystroke( + &Keystroke::parse("ctrl-alt-delete").unwrap(), + PlatformStyle::Linux + ), + "Ctrl+Alt+Delete".to_string() + ); + assert_eq!( + text_for_keystroke( + &Keystroke::parse("ctrl-alt-delete").unwrap(), + PlatformStyle::Windows + ), + "Ctrl+Alt+Delete".to_string() + ); + + assert_eq!( + text_for_keystroke( + &Keystroke::parse("shift-pageup").unwrap(), + PlatformStyle::Mac + ), + "Shift-PageUp".to_string() + ); + assert_eq!( + text_for_keystroke( + &Keystroke::parse("shift-pageup").unwrap(), + PlatformStyle::Linux + ), + "Shift+PageUp".to_string() + ); + assert_eq!( + text_for_keystroke( + &Keystroke::parse("shift-pageup").unwrap(), + PlatformStyle::Windows + ), + "Shift+PageUp".to_string() + ); + } +} diff --git a/crates/ui/src/components/label/highlighted_label.rs b/crates/ui/src/components/label/highlighted_label.rs index 6b170bb810f42bea1bdfd110852f25c4ada2366b..f96171395651132da6f6f3b97823ae028d854f67 100644 --- a/crates/ui/src/components/label/highlighted_label.rs +++ b/crates/ui/src/components/label/highlighted_label.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use std::ops::Range; use gpui::{FontWeight, HighlightStyle, StyledText}; diff --git a/crates/ui/src/components/label/label.rs b/crates/ui/src/components/label/label.rs index 898a59de775d9ec624be95b045db9ac2af5c0e56..f65596184191c27114a9af620ec710a697150e0c 100644 --- a/crates/ui/src/components/label/label.rs +++ b/crates/ui/src/components/label/label.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use gpui::{StyleRefinement, WindowContext}; use crate::{prelude::*, LabelCommon, LabelLike, LabelSize, LineHeightStyle}; diff --git a/crates/ui/src/components/label/label_like.rs b/crates/ui/src/components/label/label_like.rs index bc2fae15a7fdc44244af984803137a37b7aa37ca..0bd21eda4f34f9644e30b89ed29ed721591bd540 100644 --- a/crates/ui/src/components/label/label_like.rs +++ b/crates/ui/src/components/label/label_like.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use gpui::{relative, AnyElement, FontWeight, StyleRefinement, Styled, UnderlineStyle}; use settings::Settings; use smallvec::SmallVec; diff --git a/crates/ui/src/components/list/list.rs b/crates/ui/src/components/list/list.rs index 4bf157ef4067d80e3a52eeb327ec30c23f3d266b..e112a558ee3eeb4c16593a0dc56a63329beab593 100644 --- a/crates/ui/src/components/list/list.rs +++ b/crates/ui/src/components/list/list.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use gpui::AnyElement; use smallvec::SmallVec; diff --git a/crates/ui/src/components/list/list_header.rs b/crates/ui/src/components/list/list_header.rs index 3b15f8cd3dd09086d6ef232935f777f1440e0cff..b69426b6d1f80f1253f4cb2e866a771aa1066293 100644 --- a/crates/ui/src/components/list/list_header.rs +++ b/crates/ui/src/components/list/list_header.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use std::sync::Arc; use crate::{h_flex, prelude::*, Disclosure, Label}; diff --git a/crates/ui/src/components/list/list_item.rs b/crates/ui/src/components/list/list_item.rs index e13fb8ef265ebf5a29b0195d715f3852716e1c0f..37076737a6be0e2e0b303475aa0bb4b0d09e5ecf 100644 --- a/crates/ui/src/components/list/list_item.rs +++ b/crates/ui/src/components/list/list_item.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use std::sync::Arc; use gpui::{px, AnyElement, AnyView, ClickEvent, MouseButton, MouseDownEvent, Pixels}; diff --git a/crates/ui/src/components/list/list_separator.rs b/crates/ui/src/components/list/list_separator.rs index 0d5fdf8d494fbe9cb3b0cee18227ac070ee604fe..aa53efab372f0512738ba49754658abb56210531 100644 --- a/crates/ui/src/components/list/list_separator.rs +++ b/crates/ui/src/components/list/list_separator.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use crate::prelude::*; #[derive(IntoElement)] diff --git a/crates/ui/src/components/list/list_sub_header.rs b/crates/ui/src/components/list/list_sub_header.rs index 0ed072ebbf2c90dc71e25d40227f9adf7ab10c89..25132b76686626a0b928bbea679a8ee26d65f9c1 100644 --- a/crates/ui/src/components/list/list_sub_header.rs +++ b/crates/ui/src/components/list/list_sub_header.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use crate::prelude::*; use crate::{h_flex, Icon, IconName, IconSize, Label}; diff --git a/crates/ui/src/components/modal.rs b/crates/ui/src/components/modal.rs index dec7a14a52fe5ef1a2ee4e6347161420520af1fb..11611f9c0ffc92fc63a05842e0593bd22ba8f77c 100644 --- a/crates/ui/src/components/modal.rs +++ b/crates/ui/src/components/modal.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use crate::{ h_flex, v_flex, Clickable, Color, Headline, HeadlineSize, IconButton, IconButtonShape, IconName, Label, LabelCommon, LabelSize, Spacing, diff --git a/crates/ui/src/components/numeric_stepper.rs b/crates/ui/src/components/numeric_stepper.rs index 64ea79f21cc6def01bd08ab4d97a2753d96cc90e..39be56a455641cf9e0d811b5b9f2ce43b7f5f008 100644 --- a/crates/ui/src/components/numeric_stepper.rs +++ b/crates/ui/src/components/numeric_stepper.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use gpui::ClickEvent; use crate::{prelude::*, IconButtonShape}; diff --git a/crates/ui/src/components/popover.rs b/crates/ui/src/components/popover.rs index af20f3818663d4516f52769b46989cd74bfdfb6e..5bd6c1ed7ccbca0ca14457dda96b5d0f39acfe40 100644 --- a/crates/ui/src/components/popover.rs +++ b/crates/ui/src/components/popover.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use crate::prelude::*; use crate::v_flex; use gpui::{ diff --git a/crates/ui/src/components/popover_menu.rs b/crates/ui/src/components/popover_menu.rs index 02604b2cc6b19b320fe080026aa86545b1d7bc1a..e05888bdf600cd85d58b799df3f3a7873def792b 100644 --- a/crates/ui/src/components/popover_menu.rs +++ b/crates/ui/src/components/popover_menu.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use std::{cell::RefCell, rc::Rc}; use gpui::{ diff --git a/crates/ui/src/components/radio.rs b/crates/ui/src/components/radio.rs index f3eeb9dac000d9cec6818c495f394250062455ae..c4ceef5f8379a5c914fb874cf9c134af1f22e639 100644 --- a/crates/ui/src/components/radio.rs +++ b/crates/ui/src/components/radio.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use std::sync::Arc; use crate::prelude::*; diff --git a/crates/ui/src/components/right_click_menu.rs b/crates/ui/src/components/right_click_menu.rs index c340a4ad896ef984166d0a643fa4acf46cb975fb..f68b85016c4d1e9d9f87d74ebd5715bd013d1136 100644 --- a/crates/ui/src/components/right_click_menu.rs +++ b/crates/ui/src/components/right_click_menu.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use std::{cell::RefCell, rc::Rc}; use gpui::{ diff --git a/crates/ui/src/components/settings_container.rs b/crates/ui/src/components/settings_container.rs index df1c355e06a5143c0255df3f220e4857404e1568..56248ce528022dac966e52cf83af8964abc97abb 100644 --- a/crates/ui/src/components/settings_container.rs +++ b/crates/ui/src/components/settings_container.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use gpui::AnyElement; use smallvec::SmallVec; diff --git a/crates/ui/src/components/settings_group.rs b/crates/ui/src/components/settings_group.rs index 60939640572dab21abb183e70fb43a8a83acbdae..77b4416a4a4c95345fed975eb940a5a108112a89 100644 --- a/crates/ui/src/components/settings_group.rs +++ b/crates/ui/src/components/settings_group.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use gpui::AnyElement; use smallvec::SmallVec; diff --git a/crates/ui/src/components/stack.rs b/crates/ui/src/components/stack.rs index 74a5e80575bfe0ebe28334f4533f12b91b1fcfb2..2af0a5d3f98b084117cec30851a6146798afaedc 100644 --- a/crates/ui/src/components/stack.rs +++ b/crates/ui/src/components/stack.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use gpui::{div, Div}; use crate::StyledExt; diff --git a/crates/ui/src/components/stories.rs b/crates/ui/src/components/stories.rs index 9014f5a47082f3fe36cda5328dd9a6bf1b34e9ef..88325f2201b172435e729c299fda31dfa7a3bd10 100644 --- a/crates/ui/src/components/stories.rs +++ b/crates/ui/src/components/stories.rs @@ -1,3 +1,6 @@ +// We allow missing docs for stories as the docs will more or less be +// "This is the ___ story", which is not very useful. +#![allow(missing_docs)] mod avatar; mod button; mod checkbox; diff --git a/crates/ui/src/components/tab.rs b/crates/ui/src/components/tab.rs index 1ec4cd4aecf3ebf8003ed2dc970608444859a3a2..9540063c78dc406948d4d3a023968b2063d6cf0a 100644 --- a/crates/ui/src/components/tab.rs +++ b/crates/ui/src/components/tab.rs @@ -1,3 +1,4 @@ +#![allow(missing_docs)] use std::cmp::Ordering; use gpui::{AnyElement, IntoElement, Stateful}; diff --git a/crates/ui/src/components/tab_bar.rs b/crates/ui/src/components/tab_bar.rs index 0012c53ed810819d02e29af2f3e691a74340355e..5657721e17a215d89ee0741732c7f56f7c9900e4 100644 --- a/crates/ui/src/components/tab_bar.rs +++ b/crates/ui/src/components/tab_bar.rs @@ -1,3 +1,4 @@ +#![allow(missing_docs)] use gpui::{AnyElement, ScrollHandle}; use smallvec::SmallVec; diff --git a/crates/ui/src/components/tool_strip.rs b/crates/ui/src/components/tool_strip.rs index ced4b271ad3c4afb59b33c2e11cf30dffd805529..78767aadf73fbb184afe880ed73db154b69321ae 100644 --- a/crates/ui/src/components/tool_strip.rs +++ b/crates/ui/src/components/tool_strip.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use crate::prelude::*; use gpui::*; diff --git a/crates/ui/src/components/tooltip.rs b/crates/ui/src/components/tooltip.rs index dc02d60b36d4a30d8259fc751ed841eeab586f8b..89b89786b0dfa4fcc4b781022dcfa3ac052acb38 100644 --- a/crates/ui/src/components/tooltip.rs +++ b/crates/ui/src/components/tooltip.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use gpui::{Action, AnyView, FocusHandle, IntoElement, Render, VisualContext}; use settings::Settings; use theme::ThemeSettings; diff --git a/crates/ui/src/key_bindings.rs b/crates/ui/src/key_bindings.rs deleted file mode 100644 index 7746d096fed9c0f0e274b8ced731bb88bcd82183..0000000000000000000000000000000000000000 --- a/crates/ui/src/key_bindings.rs +++ /dev/null @@ -1,170 +0,0 @@ -use gpui::{Action, FocusHandle, KeyBinding, Keystroke, WindowContext}; - -use crate::PlatformStyle; - -/// Returns a textual representation of the key binding for the given [`Action`]. -pub fn text_for_action(action: &dyn Action, cx: &mut WindowContext) -> Option { - let key_binding = cx.bindings_for_action(action).last().cloned()?; - Some(text_for_key_binding(key_binding, PlatformStyle::platform())) -} - -/// Returns a textual representation of the key binding for the given [`Action`] -/// as if the provided [`FocusHandle`] was focused. -pub fn text_for_action_in( - action: &dyn Action, - focus: &FocusHandle, - cx: &mut WindowContext, -) -> Option { - let key_binding = cx.bindings_for_action_in(action, focus).last().cloned()?; - Some(text_for_key_binding(key_binding, PlatformStyle::platform())) -} - -/// Returns a textual representation of the given key binding for the specified platform. -pub fn text_for_key_binding(key_binding: KeyBinding, platform_style: PlatformStyle) -> String { - key_binding - .keystrokes() - .iter() - .map(|keystroke| text_for_keystroke(keystroke, platform_style)) - .collect::>() - .join(" ") -} - -/// Returns a textual representation of the given [`Keystroke`]. -pub fn text_for_keystroke(keystroke: &Keystroke, platform_style: PlatformStyle) -> String { - let mut text = String::new(); - - let delimiter = match platform_style { - PlatformStyle::Mac => '-', - PlatformStyle::Linux | PlatformStyle::Windows => '+', - }; - - if keystroke.modifiers.function { - match platform_style { - PlatformStyle::Mac => text.push_str("fn"), - PlatformStyle::Linux | PlatformStyle::Windows => text.push_str("Fn"), - } - - text.push(delimiter); - } - - if keystroke.modifiers.control { - match platform_style { - PlatformStyle::Mac => text.push_str("Control"), - PlatformStyle::Linux | PlatformStyle::Windows => text.push_str("Ctrl"), - } - - text.push(delimiter); - } - - if keystroke.modifiers.alt { - match platform_style { - PlatformStyle::Mac => text.push_str("Option"), - PlatformStyle::Linux | PlatformStyle::Windows => text.push_str("Alt"), - } - - text.push(delimiter); - } - - if keystroke.modifiers.platform { - match platform_style { - PlatformStyle::Mac => text.push_str("Command"), - PlatformStyle::Linux => text.push_str("Super"), - PlatformStyle::Windows => text.push_str("Win"), - } - - text.push(delimiter); - } - - if keystroke.modifiers.shift { - match platform_style { - PlatformStyle::Mac | PlatformStyle::Linux | PlatformStyle::Windows => { - text.push_str("Shift") - } - } - - text.push(delimiter); - } - - fn capitalize(str: &str) -> String { - let mut chars = str.chars(); - match chars.next() { - None => String::new(), - Some(first_char) => first_char.to_uppercase().collect::() + chars.as_str(), - } - } - - let key = match keystroke.key.as_str() { - "pageup" => "PageUp", - "pagedown" => "PageDown", - key => &capitalize(key), - }; - - text.push_str(key); - - text -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_text_for_keystroke() { - assert_eq!( - text_for_keystroke(&Keystroke::parse("cmd-c").unwrap(), PlatformStyle::Mac), - "Command-C".to_string() - ); - assert_eq!( - text_for_keystroke(&Keystroke::parse("cmd-c").unwrap(), PlatformStyle::Linux), - "Super+C".to_string() - ); - assert_eq!( - text_for_keystroke(&Keystroke::parse("cmd-c").unwrap(), PlatformStyle::Windows), - "Win+C".to_string() - ); - - assert_eq!( - text_for_keystroke( - &Keystroke::parse("ctrl-alt-delete").unwrap(), - PlatformStyle::Mac - ), - "Control-Option-Delete".to_string() - ); - assert_eq!( - text_for_keystroke( - &Keystroke::parse("ctrl-alt-delete").unwrap(), - PlatformStyle::Linux - ), - "Ctrl+Alt+Delete".to_string() - ); - assert_eq!( - text_for_keystroke( - &Keystroke::parse("ctrl-alt-delete").unwrap(), - PlatformStyle::Windows - ), - "Ctrl+Alt+Delete".to_string() - ); - - assert_eq!( - text_for_keystroke( - &Keystroke::parse("shift-pageup").unwrap(), - PlatformStyle::Mac - ), - "Shift-PageUp".to_string() - ); - assert_eq!( - text_for_keystroke( - &Keystroke::parse("shift-pageup").unwrap(), - PlatformStyle::Linux - ), - "Shift+PageUp".to_string() - ); - assert_eq!( - text_for_keystroke( - &Keystroke::parse("shift-pageup").unwrap(), - PlatformStyle::Windows - ), - "Shift+PageUp".to_string() - ); - } -} diff --git a/crates/ui/src/prelude.rs b/crates/ui/src/prelude.rs index 895c755c786c109462eeca504e53316a6cc42807..d01ac11bc3e43c937830034df73e21ffe48ff944 100644 --- a/crates/ui/src/prelude.rs +++ b/crates/ui/src/prelude.rs @@ -7,16 +7,17 @@ pub use gpui::{ WindowContext, }; -pub use crate::clickable::*; -pub use crate::disableable::*; -pub use crate::fixed::*; -pub use crate::selectable::*; pub use crate::styles::{rems_from_px, vh, vw, PlatformStyle, StyledTypography, TextSize}; -pub use crate::visible_on_hover::*; +pub use crate::traits::clickable::*; +pub use crate::traits::disableable::*; +pub use crate::traits::fixed::*; +pub use crate::traits::selectable::*; +pub use crate::traits::styled_ext::*; +pub use crate::traits::visible_on_hover::*; pub use crate::Spacing; pub use crate::{h_flex, v_flex}; pub use crate::{Button, ButtonSize, ButtonStyle, IconButton, SelectableButton}; -pub use crate::{ButtonCommon, Color, StyledExt}; +pub use crate::{ButtonCommon, Color}; pub use crate::{Headline, HeadlineSize}; pub use crate::{Icon, IconName, IconPosition, IconSize}; pub use crate::{Label, LabelCommon, LabelSize, LineHeightStyle}; diff --git a/crates/ui/src/styles/appearance.rs b/crates/ui/src/styles/appearance.rs index 57d4757a3674e1b0372edb24765dde159ee759f6..3b014b733c9fc286c335352fa4e8b016bf9ab50a 100644 --- a/crates/ui/src/styles/appearance.rs +++ b/crates/ui/src/styles/appearance.rs @@ -1,14 +1,8 @@ use crate::prelude::*; use gpui::{WindowBackgroundAppearance, WindowContext}; -use theme::Appearance; - -/// Returns the current [Appearance]. -pub fn appearance(cx: &WindowContext) -> Appearance { - cx.theme().appearance -} /// Returns the [WindowBackgroundAppearance]. -pub fn window_appearance(cx: &WindowContext) -> WindowBackgroundAppearance { +fn window_appearance(cx: &WindowContext) -> WindowBackgroundAppearance { cx.theme().styles.window_background_appearance } diff --git a/crates/ui/src/styles/color.rs b/crates/ui/src/styles/color.rs index b35728e478fb5e9aed6edd59e7288391d1052645..fe8de2ff734966cf064e3e46977a4cf6f15642ad 100644 --- a/crates/ui/src/styles/color.rs +++ b/crates/ui/src/styles/color.rs @@ -5,28 +5,63 @@ use theme::ActiveTheme; #[derive(Debug, Default, PartialEq, Copy, Clone)] pub enum Color { #[default] + /// The default text color. Might be known as "foreground" or "primary" in + /// some theme systems. + /// + /// For less emphasis, consider using [`Color::Muted`] or [`Color::Hidden`]. Default, + /// A text color used for accents, such as links or highlights. Accent, + /// A color used to indicate a conflict, such as a version control merge conflict, or a conflict between a file in the editor and the file system. + Conflict, + /// A color used to indicate a newly created item, such as a new file in + /// version control, or a new file on disk. Created, + /// It is highly, HIGHLY recommended not to use this! Using this color + /// means detaching it from any semantic meaning across themes. + /// + /// A custom color specified by an HSLA value. + Custom(Hsla), + /// A color used to indicate a deleted item, such as a file removed from version control. Deleted, + /// A color used for disabled UI elements or text, like a disabled button or menu item. Disabled, + /// A color used to indicate an error condition, or something the user + /// cannot do. In very rare cases, it might be used to indicate dangerous or + /// destructive action. Error, + /// A color used for elements that represent something that is hidden, like + /// a hidden file, or an element that should be visually de-emphasized. Hidden, + /// A color used for hint or suggestion text, often a blue color. Use this + /// color to represent helpful, or semantically neutral information. Hint, + /// A color used for items that are intentionally ignored, such as files ignored by version control. + Ignored, + /// A color used for informational messages or status indicators, often a blue color. Info, + /// A color used to indicate a modified item, such as an edited file, or a modified entry in version control. Modified, - Conflict, - Ignored, + /// A color used for text or UI elements that should be visually muted or de-emphasized. + /// + /// For more emphasis, consider using [`Color::Default`]. + /// + /// For less emphasis, consider using [`Color::Hidden`]. Muted, + /// A color used for placeholder text in input fields. Placeholder, + /// A color associated with a specific player number. Player(u32), + /// A color used to indicate selected text or UI elements. Selected, + /// A color used to indicate a successful operation or status. Success, + /// A color used to indicate a warning condition. Warning, - Custom(Hsla), } impl Color { + /// Returns the Color's HSLA value. pub fn color(&self, cx: &WindowContext) -> Hsla { match self { Color::Default => cx.theme().colors().text, diff --git a/crates/ui/src/styles/docs/elevation.md b/crates/ui/src/styles/docs/elevation.md deleted file mode 100644 index 677fd030fd9ba14ff968f7338fe8924d554564dc..0000000000000000000000000000000000000000 --- a/crates/ui/src/styles/docs/elevation.md +++ /dev/null @@ -1,44 +0,0 @@ -# Elevation - -Elevation can be thought of as the physical closeness of an element to the user. Elements with lower elevations are physically further away from the user on the z-axis and appear to be underneath elements with higher elevations. - -Material Design 3 has a some great visualizations of elevation that may be helpful to understanding the mental modal of elevation. [Material Design – Elevation](https://m3.material.io/styles/elevation/overview) - -## Elevation Levels - -1. App Background (e.x.: Workspace, system window) -1. UI Surface (e.x.: Title Bar, Panel, Tab Bar) -1. Elevated Surface (e.x.: Palette, Notification, Floating Window) -1. Wash -1. Modal Surfaces (e.x.: Modal) -1. Dragged Element (This is a special case, see Layer section below) - -### App Background - -The app background constitutes the lowest elevation layer, appearing behind all other surfaces and components. It is predominantly used for the background color of the app. - -### Surface - -The Surface elevation level, located above the app background, is the standard level for all elements - -Example Elements: Title Bar, Panel, Tab Bar, Editor - -### Elevated Surface - -Non-Modal Elevated Surfaces appear above the UI 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. - -Examples: Notifications, Palettes, Detached/Floating Windows, Detached/Floating Panels - -You could imagine a variant of the assistant that floats in a window above the editor on this elevation, or a floating terminal window that becomes less opaque when not focused. - -### Wash - -Wash denotes a distinct elevation reserved to isolate app UI layers from high elevation components such as modals, notifications, and overlaid panels. The wash may not consistently be visible when these components are active. This layer is often referred to as a scrim or overlay and the background color of the wash is typically deployed in its design. - -### Modal Surfaces - -Modal Surfaces are used for elements that should appear above all other UI elements and are located above the wash layer. This is the maximum elevation at which UI elements can be rendered - -Elements rendered at this layer 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 layer. diff --git a/crates/ui/src/styles/elevation.rs b/crates/ui/src/styles/elevation.rs index c067802119b1ee8e3c2112be25a9330c5f9edef7..722111b46c49ffad01117e6670fc33f0ff03ca54 100644 --- a/crates/ui/src/styles/elevation.rs +++ b/crates/ui/src/styles/elevation.rs @@ -1,31 +1,32 @@ use gpui::{hsla, point, px, BoxShadow}; use smallvec::{smallvec, SmallVec}; -#[doc = include_str!("docs/elevation.md")] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Elevation { - ElevationIndex(ElevationIndex), - LayerIndex(LayerIndex), - ElementIndex(ElementIndex), -} - -impl From for Elevation { - fn from(val: ElevationIndex) -> Self { - Elevation::ElevationIndex(val) - } -} - +/// Today, elevation is primarily used to add shadows to elements, and set the correct background for elements like buttons. +/// +/// Elevation can be thought of as the physical closeness of an element to the +/// user. Elements with lower elevations are physically further away on the +/// z-axis and appear to be underneath elements with higher elevations. +/// +/// In the future, a more complete approach to elevation may be added. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ElevationIndex { + /// On the layer of the app background. This is under panels, panes, and + /// other surfaces. Background, + /// The primary surface – Contains panels, panes, containers, etc. Surface, + /// A surface that is elevated above the primary surface. but below washes, models, and dragged elements. ElevatedSurface, + /// A surface that is above all non-modal surfaces, and separates the app from focused intents, like dialogs, alerts, modals, etc. Wash, + /// A surface above the [ElevationIndex::Wash] that is used for dialogs, alerts, modals, etc. ModalSurface, + /// A surface above all other surfaces, reserved exclusively for dragged elements, like a dragged file, tab or other draggable element. DraggedElement, } impl ElevationIndex { + /// Returns an appropriate shadow for the given elevation index. pub fn shadow(self) -> SmallVec<[BoxShadow; 2]> { match self { ElevationIndex::Surface => smallvec![], @@ -62,21 +63,3 @@ impl ElevationIndex { } } } - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum LayerIndex { - BehindElement, - Element, - ElevatedElement, -} - -/// An appropriate z-index for the given layer based on its intended usage. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum ElementIndex { - Effect, - Background, - Tint, - Highlight, - Content, - Overlay, -} diff --git a/crates/ui/src/styles/spacing.rs b/crates/ui/src/styles/spacing.rs index 282980fcaf5e1c3e6e0552256b6b5fd01ad24088..a2089d9586bd45465f8c69e53390e56ba7f57252 100644 --- a/crates/ui/src/styles/spacing.rs +++ b/crates/ui/src/styles/spacing.rs @@ -4,6 +4,11 @@ use theme::{ThemeSettings, UiDensity}; use crate::{rems_from_px, BASE_REM_SIZE_IN_PX}; +/// A dynamic spacing system that adjusts spacing based on +/// [UiDensity]. +/// +/// When possible, [Spacing] should be used over manual +/// or built-in spacing values in places dynamic spacing is needed. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Spacing { /// No spacing @@ -38,6 +43,7 @@ pub enum Spacing { } impl Spacing { + /// Returns the spacing's scaling ratio in pixels. pub fn spacing_ratio(self, cx: &WindowContext) -> f32 { match ThemeSettings::get_global(cx).ui_density { UiDensity::Compact => match self { @@ -73,10 +79,12 @@ impl Spacing { } } + /// Returns the spacing's value in rems. pub fn rems(self, cx: &WindowContext) -> Rems { rems(self.spacing_ratio(cx)) } + /// Returns the spacing's value in pixels. pub fn px(self, cx: &WindowContext) -> Pixels { let ui_font_size_f32: f32 = ThemeSettings::get_global(cx).ui_font_size.into(); @@ -84,10 +92,14 @@ impl Spacing { } } -pub fn user_spacing_style(cx: &WindowContext) -> UiDensity { +fn user_spacing_style(cx: &WindowContext) -> UiDensity { ThemeSettings::get_global(cx).ui_density } +/// Returns a custom spacing value based on the current [`UiDensity`]. +/// +/// If you use this, talk to @iamnbutler and let me know what you're doing +/// that needs custom spacing– I'd love to understand so we can extend the system further and remove the need for this. pub fn custom_spacing(cx: &WindowContext, size: f32) -> Rems { rems_from_px(size * user_spacing_style(cx).spacing_ratio()) } diff --git a/crates/ui/src/styles/typography.rs b/crates/ui/src/styles/typography.rs index 4afd3b93036c2fa0b81ceee0bd6c808fa2b6c2b5..ef9c946ed54c0492f8a104133f0bb15ee11a8751 100644 --- a/crates/ui/src/styles/typography.rs +++ b/crates/ui/src/styles/typography.rs @@ -87,6 +87,7 @@ pub trait StyledTypography: Styled + Sized { impl StyledTypography for E {} +/// A utility for getting the size of various semantic text sizes. #[derive(Debug, Default, Clone)] pub enum TextSize { /// The default size for UI text. @@ -128,6 +129,7 @@ pub enum TextSize { } impl TextSize { + /// Returns the text size in rems. pub fn rems(self, cx: &WindowContext) -> Rems { let theme_settings = ThemeSettings::get_global(cx); @@ -143,20 +145,27 @@ impl TextSize { } /// The size of a [`Headline`] element +/// +/// Defaults to a Major Second scale. #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)] pub enum HeadlineSize { + /// An extra small headline - `~14px` @16px/rem XSmall, + /// A small headline - `16px` @16px/rem Small, #[default] + /// A medium headline - `~18px` @16px/rem Medium, + /// A large headline - `~20px` @16px/rem Large, + /// An extra large headline - `~22px` @16px/rem XLarge, } impl HeadlineSize { - pub fn size(self) -> Rems { + /// Returns the headline size in rems. + pub fn rems(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), @@ -165,6 +174,7 @@ impl HeadlineSize { } } + /// Returns the line height for the headline size. pub fn line_height(self) -> Rems { match self { Self::XSmall => rems(1.6), @@ -176,6 +186,8 @@ impl HeadlineSize { } } +/// A headline element, used to emphasize some text and +/// create a visual hierarchy. #[derive(IntoElement)] pub struct Headline { size: HeadlineSize, @@ -190,13 +202,14 @@ impl RenderOnce for Headline { div() .font(ui_font) .line_height(self.size.line_height()) - .text_size(self.size.size()) + .text_size(self.size.rems()) .text_color(cx.theme().colors().text) .child(self.text) } } impl Headline { + /// Create a new headline element. pub fn new(text: impl Into) -> Self { Self { size: HeadlineSize::default(), @@ -205,11 +218,13 @@ impl Headline { } } + /// Set the size of the headline. pub fn size(mut self, size: HeadlineSize) -> Self { self.size = size; self } + /// Set the color of the headline. pub fn color(mut self, color: Color) -> Self { self.color = color; self diff --git a/crates/ui/src/tests.rs b/crates/ui/src/tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..3f26326a056f39f03c44e96eb6eb3b102428319b --- /dev/null +++ b/crates/ui/src/tests.rs @@ -0,0 +1 @@ +mod path_str; diff --git a/crates/ui/src/path_str.rs b/crates/ui/src/tests/path_str.rs similarity index 54% rename from crates/ui/src/path_str.rs rename to crates/ui/src/tests/path_str.rs index 2ebb3fedb36266f41b71be0c66bd362d7edded53..6c1545ec7104d026c18cee8292ace7a010960e99 100644 --- a/crates/ui/src/path_str.rs +++ b/crates/ui/src/tests/path_str.rs @@ -1,3 +1,5 @@ +// We need to test [ui_macros::DerivePathStr] here as we can't invoke it +// in the `ui_macros` crate. #[cfg(test)] mod tests { use strum::EnumString; @@ -8,26 +10,26 @@ mod tests { #[derive(Debug, EnumString, DerivePathStr)] #[strum(serialize_all = "snake_case")] #[path_str(prefix = "test_prefix")] - enum MyEnum { + enum SomeAsset { FooBar, Baz, } - assert_eq!(MyEnum::FooBar.path(), "test_prefix/foo_bar"); - assert_eq!(MyEnum::Baz.path(), "test_prefix/baz"); + assert_eq!(SomeAsset::FooBar.path(), "test_prefix/foo_bar"); + assert_eq!(SomeAsset::Baz.path(), "test_prefix/baz"); } #[test] fn test_derive_path_str_with_prefix_and_suffix() { #[derive(Debug, EnumString, DerivePathStr)] #[strum(serialize_all = "snake_case")] - #[path_str(prefix = "test_prefix", suffix = ".txt")] - enum MyEnum { + #[path_str(prefix = "test_prefix", suffix = ".svg")] + enum SomeAsset { FooBar, Baz, } - assert_eq!(MyEnum::FooBar.path(), "test_prefix/foo_bar.txt"); - assert_eq!(MyEnum::Baz.path(), "test_prefix/baz.txt"); + assert_eq!(SomeAsset::FooBar.path(), "test_prefix/foo_bar.svg"); + assert_eq!(SomeAsset::Baz.path(), "test_prefix/baz.svg"); } } diff --git a/crates/ui/src/traits.rs b/crates/ui/src/traits.rs new file mode 100644 index 0000000000000000000000000000000000000000..7e52f2a86756470646df6605ee034281098c9d8b --- /dev/null +++ b/crates/ui/src/traits.rs @@ -0,0 +1,6 @@ +pub mod clickable; +pub mod disableable; +pub mod fixed; +pub mod selectable; +pub mod styled_ext; +pub mod visible_on_hover; diff --git a/crates/ui/src/clickable.rs b/crates/ui/src/traits/clickable.rs similarity index 100% rename from crates/ui/src/clickable.rs rename to crates/ui/src/traits/clickable.rs diff --git a/crates/ui/src/disableable.rs b/crates/ui/src/traits/disableable.rs similarity index 100% rename from crates/ui/src/disableable.rs rename to crates/ui/src/traits/disableable.rs diff --git a/crates/ui/src/fixed.rs b/crates/ui/src/traits/fixed.rs similarity index 100% rename from crates/ui/src/fixed.rs rename to crates/ui/src/traits/fixed.rs diff --git a/crates/ui/src/selectable.rs b/crates/ui/src/traits/selectable.rs similarity index 100% rename from crates/ui/src/selectable.rs rename to crates/ui/src/traits/selectable.rs diff --git a/crates/ui/src/styled_ext.rs b/crates/ui/src/traits/styled_ext.rs similarity index 100% rename from crates/ui/src/styled_ext.rs rename to crates/ui/src/traits/styled_ext.rs diff --git a/crates/ui/src/visible_on_hover.rs b/crates/ui/src/traits/visible_on_hover.rs similarity index 85% rename from crates/ui/src/visible_on_hover.rs rename to crates/ui/src/traits/visible_on_hover.rs index aefa7ac10c50646edca24f6ff2219418a44c8be9..fc0bb837d7412318f76205e76a619d6845e8fb63 100644 --- a/crates/ui/src/visible_on_hover.rs +++ b/crates/ui/src/traits/visible_on_hover.rs @@ -1,5 +1,7 @@ use gpui::{InteractiveElement, SharedString, Styled}; +/// A trait for elements that can be made visible on hover by +/// tracking a specific group. pub trait VisibleOnHover { /// Sets the element to only be visible when the specified group is hovered. /// diff --git a/crates/ui/src/ui.rs b/crates/ui/src/ui.rs index 4f5d6314bea6a683bd422931466253fdc61984fb..101de4f3efa1adc7c8ddf93eeba79bceb1ac61a9 100644 --- a/crates/ui/src/ui.rs +++ b/crates/ui/src/ui.rs @@ -1,28 +1,22 @@ +#![deny(missing_docs)] + //! # UI – Zed UI Primitives & Components //! //! This crate provides a set of UI primitives and components that are used to build all of the elements in Zed's UI. //! +//! ## Related Crates: +//! +//! - [`ui_macros`] - proc_macros support for this crate +//! - [`ui_input`] - the single line input component +//! -mod clickable; mod components; -mod disableable; -mod fixed; -mod key_bindings; -mod path_str; pub mod prelude; -mod selectable; -mod styled_ext; mod styles; +mod tests; +mod traits; pub mod utils; -mod visible_on_hover; -mod with_rem_size; -pub use clickable::*; pub use components::*; -pub use disableable::*; -pub use fixed::*; -pub use key_bindings::*; pub use prelude::*; -pub use styled_ext::*; pub use styles::*; -pub use with_rem_size::*; diff --git a/crates/ui/src/utils.rs b/crates/ui/src/utils.rs index ed1fec690fc738be2bee5d621c7fc53f0c0f6b9e..b68d6e6bbdba61dd7a369b079e34d83323894dd5 100644 --- a/crates/ui/src/utils.rs +++ b/crates/ui/src/utils.rs @@ -1,5 +1,7 @@ -//! UI-related utilities (e.g. converting dates to a human-readable form). +//! UI-related utilities mod format_distance; +mod with_rem_size; pub use format_distance::*; +pub use with_rem_size::*; diff --git a/crates/ui/src/utils/format_distance.rs b/crates/ui/src/utils/format_distance.rs index 2abcee6684e3000ec46bd15e472f9b5615d06015..af4f0d95052b28567def82a438cc3e60a304f438 100644 --- a/crates/ui/src/utils/format_distance.rs +++ b/crates/ui/src/utils/format_distance.rs @@ -1,3 +1,6 @@ +// This won't be documented further as it is intended to be removed, or merged with the `time_format` crate. +#![allow(missing_docs)] + use chrono::{DateTime, Local, NaiveDateTime}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] diff --git a/crates/ui/src/with_rem_size.rs b/crates/ui/src/utils/with_rem_size.rs similarity index 95% rename from crates/ui/src/with_rem_size.rs rename to crates/ui/src/utils/with_rem_size.rs index f286177efb63491fe8b77113c7c695fd89eab34c..9011d1e28e95f035cb9e9d4e5fac4f69f4be3139 100644 --- a/crates/ui/src/with_rem_size.rs +++ b/crates/ui/src/utils/with_rem_size.rs @@ -10,6 +10,8 @@ pub struct WithRemSize { } impl WithRemSize { + /// Create a new [WithRemSize] element, which sets a + /// particular rem size for its children. pub fn new(rem_size: impl Into) -> Self { Self { div: div(),