ui
crate docs & spring cleaning (#18768)
Similar to https://github.com/zed-industries/zed/pull/18690 & https://github.com/zed-industries/zed/pull/18695, this PR enables required docs for `ui` and does some cleanup. Changes: - Enables the `deny(missing_docs)` crate-wide. - Adds `allow(missing_docs)` on many modules until folks pick them up to document them - Documents some modules (all in `ui/src/styles`) - Crate root-level organization: Traits move to `traits`, other misc organization - Cleaned out a bunch of unused code. Note: I'd like to remove `utils/format_distance` but the assistant panel uses it. To move it over to use the `time_format` crate we may need to update it to use `time` instead of `chrono`. Needs more investigation. Release Notes: - N/A
This commit is contained in:
parent
c9bee9f81f
commit
8376dd2011
66 changed files with 405 additions and 364 deletions
|
@ -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)
|
||||
|
|
|
@ -910,7 +910,7 @@ impl PromptLibrary {
|
|||
.features
|
||||
.clone(),
|
||||
font_size: HeadlineSize::Large
|
||||
.size()
|
||||
.rems()
|
||||
.into(),
|
||||
font_weight: settings.ui_font.weight,
|
||||
line_height: relative(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use gpui::{AnyElement, Hsla, Render};
|
||||
use story::Story;
|
||||
|
||||
use ui::{prelude::*, WithRemSize};
|
||||
use ui::{prelude::*, utils::WithRemSize};
|
||||
|
||||
pub struct WithRemSizeStory;
|
||||
|
||||
|
|
|
@ -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<ImageSource>) -> 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<Hsla>) -> 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<E: IntoElement>(mut self, indicator: impl Into<Option<E>>) -> 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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(missing_docs)]
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(missing_docs)]
|
||||
use gpui::{AnyView, DefiniteLength};
|
||||
|
||||
use crate::{prelude::*, ElevationIndex, IconPosition, KeyBinding, Spacing};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(missing_docs)]
|
||||
use crate::{prelude::*, Icon, IconName, IconSize};
|
||||
|
||||
/// An icon that appears within a button.
|
||||
|
|
|
@ -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<Elevation>, cx: &mut WindowContext) -> Hsla {
|
||||
fn element_bg_from_elevation(elevation: Option<ElevationIndex>, 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<Elevation>, cx: &mut WindowContex
|
|||
impl ButtonStyle {
|
||||
pub(crate) fn enabled(
|
||||
self,
|
||||
elevation: Option<Elevation>,
|
||||
elevation: Option<ElevationIndex>,
|
||||
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>,
|
||||
elevation: Option<ElevationIndex>,
|
||||
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>,
|
||||
elevation: Option<ElevationIndex>,
|
||||
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<ButtonStyle>,
|
||||
pub(super) width: Option<DefiniteLength>,
|
||||
pub(super) height: Option<DefiniteLength>,
|
||||
pub(super) layer: Option<Elevation>,
|
||||
pub(super) layer: Option<ElevationIndex>,
|
||||
size: ButtonSize,
|
||||
rounding: Option<ButtonLikeRounding>,
|
||||
tooltip: Option<Box<dyn Fn(&mut WindowContext) -> 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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(missing_docs)]
|
||||
use gpui::{AnyView, DefiniteLength};
|
||||
|
||||
use super::button_like::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(missing_docs)]
|
||||
use gpui::{AnyView, ClickEvent};
|
||||
|
||||
use crate::{prelude::*, ButtonLike, ButtonLikeRounding, ElevationIndex};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(missing_docs)]
|
||||
mod checkbox_with_label;
|
||||
|
||||
pub use checkbox_with_label::*;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use gpui::{div, prelude::*, ElementId, IntoElement, Styled, WindowContext};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{prelude::*, Checkbox};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(missing_docs)]
|
||||
use std::sync::Arc;
|
||||
|
||||
use gpui::{ClickEvent, CursorStyle};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(missing_docs)]
|
||||
use gpui::{Hsla, IntoElement};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(missing_docs)]
|
||||
use gpui::{AnchorCorner, ClickEvent, CursorStyle, MouseButton, View};
|
||||
|
||||
use crate::{prelude::*, ContextMenu, PopoverMenu};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(missing_docs)]
|
||||
use crate::prelude::*;
|
||||
use gpui::{AnyElement, StyleRefinement};
|
||||
use smallvec::SmallVec;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(missing_docs)]
|
||||
use gpui::{svg, AnimationElement, Hsla, IntoElement, Rems, Transformation};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::{EnumIter, EnumString, IntoStaticStr};
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(missing_docs)]
|
||||
use crate::{prelude::*, AnyIcon};
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
|
@ -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<String> {
|
||||
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<String> {
|
||||
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::<Vec<_>>()
|
||||
.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::<String>() + 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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use std::ops::Range;
|
||||
|
||||
use gpui::{FontWeight, HighlightStyle, StyledText};
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use gpui::{StyleRefinement, WindowContext};
|
||||
|
||||
use crate::{prelude::*, LabelCommon, LabelLike, LabelSize, LineHeightStyle};
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use gpui::{relative, AnyElement, FontWeight, StyleRefinement, Styled, UnderlineStyle};
|
||||
use settings::Settings;
|
||||
use smallvec::SmallVec;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use gpui::AnyElement;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{h_flex, prelude::*, Disclosure, Label};
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use gpui::{px, AnyElement, AnyView, ClickEvent, MouseButton, MouseDownEvent, Pixels};
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(IntoElement)]
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{h_flex, Icon, IconName, IconSize, Label};
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use crate::{
|
||||
h_flex, v_flex, Clickable, Color, Headline, HeadlineSize, IconButton, IconButtonShape,
|
||||
IconName, Label, LabelCommon, LabelSize, Spacing,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use gpui::ClickEvent;
|
||||
|
||||
use crate::{prelude::*, IconButtonShape};
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::v_flex;
|
||||
use gpui::{
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
use gpui::{
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
use gpui::{
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use gpui::AnyElement;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use gpui::AnyElement;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use gpui::{div, Div};
|
||||
|
||||
use crate::StyledExt;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(missing_docs)]
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use gpui::{AnyElement, IntoElement, Stateful};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(missing_docs)]
|
||||
use gpui::{AnyElement, ScrollHandle};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use crate::prelude::*;
|
||||
use gpui::*;
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use gpui::{Action, AnyView, FocusHandle, IntoElement, Render, VisualContext};
|
||||
use settings::Settings;
|
||||
use theme::ThemeSettings;
|
||||
|
|
|
@ -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<String> {
|
||||
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<String> {
|
||||
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::<Vec<_>>()
|
||||
.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::<String>() + 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()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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};
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
Created,
|
||||
Deleted,
|
||||
Disabled,
|
||||
Error,
|
||||
Hidden,
|
||||
Hint,
|
||||
Info,
|
||||
Modified,
|
||||
/// 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,
|
||||
Ignored,
|
||||
Muted,
|
||||
Placeholder,
|
||||
Player(u32),
|
||||
Selected,
|
||||
Success,
|
||||
Warning,
|
||||
/// 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,
|
||||
/// 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,
|
||||
}
|
||||
|
||||
impl Color {
|
||||
/// Returns the Color's HSLA value.
|
||||
pub fn color(&self, cx: &WindowContext) -> Hsla {
|
||||
match self {
|
||||
Color::Default => cx.theme().colors().text,
|
||||
|
|
|
@ -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.
|
|
@ -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<ElevationIndex> 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,
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@ pub trait StyledTypography: Styled + Sized {
|
|||
|
||||
impl<E: Styled> 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<SharedString>) -> 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
|
||||
|
|
1
crates/ui/src/tests.rs
Normal file
1
crates/ui/src/tests.rs
Normal file
|
@ -0,0 +1 @@
|
|||
mod path_str;
|
|
@ -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");
|
||||
}
|
||||
}
|
6
crates/ui/src/traits.rs
Normal file
6
crates/ui/src/traits.rs
Normal file
|
@ -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;
|
|
@ -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.
|
||||
///
|
|
@ -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::*;
|
||||
|
|
|
@ -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::*;
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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<Pixels>) -> Self {
|
||||
Self {
|
||||
div: div(),
|
Loading…
Add table
Add a link
Reference in a new issue