Merge Component
and ComponentPreview
trait (#28365)
- Merge `Component` and `ComponentPreview` trait - Adds a number of component previews - Removes a number of stories Release Notes: - N/A
This commit is contained in:
parent
b15ee1b1cc
commit
c05bf096f8
52 changed files with 3276 additions and 1848 deletions
50
Cargo.lock
generated
50
Cargo.lock
generated
|
@ -3329,6 +3329,15 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "convert_case"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-segmentation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "convert_case"
|
name = "convert_case"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
@ -4461,6 +4470,32 @@ dependencies = [
|
||||||
"workspace-hack",
|
"workspace-hack",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "documented"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc6db32f0995bc4553d2de888999075acd0dbeef75ba923503f6a724263dc6f3"
|
||||||
|
dependencies = [
|
||||||
|
"documented-macros",
|
||||||
|
"phf",
|
||||||
|
"thiserror 1.0.69",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "documented-macros"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a394bb35929b58f9a5fd418f7c6b17a4b616efcc1e53e6995ca123948f87e5fa"
|
||||||
|
dependencies = [
|
||||||
|
"convert_case 0.6.0",
|
||||||
|
"itertools 0.13.0",
|
||||||
|
"optfield",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"strum",
|
||||||
|
"syn 2.0.100",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dotenvy"
|
name = "dotenvy"
|
||||||
version = "0.15.7"
|
version = "0.15.7"
|
||||||
|
@ -7875,7 +7910,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"windows-targets 0.48.5",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -9542,6 +9577,17 @@ dependencies = [
|
||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "optfield"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa59f025cde9c698fcb4fcb3533db4621795374065bee908215263488f2d2a1d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.100",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "option-ext"
|
name = "option-ext"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -15349,6 +15395,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"component",
|
"component",
|
||||||
|
"documented",
|
||||||
"gpui",
|
"gpui",
|
||||||
"icons",
|
"icons",
|
||||||
"itertools 0.14.0",
|
"itertools 0.14.0",
|
||||||
|
@ -17614,6 +17661,7 @@ dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"inout",
|
"inout",
|
||||||
"itertools 0.12.1",
|
"itertools 0.12.1",
|
||||||
|
"itertools 0.13.0",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"libsqlite3-sys",
|
"libsqlite3-sys",
|
||||||
|
|
|
@ -3,37 +3,62 @@ use std::ops::{Deref, DerefMut};
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use gpui::{AnyElement, App, IntoElement, RenderOnce, SharedString, Window, div, prelude::*, px};
|
use gpui::{
|
||||||
|
AnyElement, App, IntoElement, RenderOnce, SharedString, Window, div, pattern_slash, prelude::*,
|
||||||
|
px, rems,
|
||||||
|
};
|
||||||
use linkme::distributed_slice;
|
use linkme::distributed_slice;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use theme::ActiveTheme;
|
use theme::ActiveTheme;
|
||||||
|
|
||||||
pub trait Component {
|
pub trait Component {
|
||||||
fn scope() -> Option<ComponentScope>;
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::None
|
||||||
|
}
|
||||||
fn name() -> &'static str {
|
fn name() -> &'static str {
|
||||||
std::any::type_name::<Self>()
|
std::any::type_name::<Self>()
|
||||||
}
|
}
|
||||||
|
/// Returns a name that the component should be sorted by.
|
||||||
|
///
|
||||||
|
/// Implement this if the component should be sorted in an alternate order than its name.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
///
|
||||||
|
/// For example, to group related components together when sorted:
|
||||||
|
///
|
||||||
|
/// - Button -> ButtonA
|
||||||
|
/// - IconButton -> ButtonBIcon
|
||||||
|
/// - ToggleButton -> ButtonCToggle
|
||||||
|
///
|
||||||
|
/// This naming scheme keeps these components together and allows them to /// be sorted in a logical order.
|
||||||
|
fn sort_name() -> &'static str {
|
||||||
|
Self::name()
|
||||||
|
}
|
||||||
fn description() -> Option<&'static str> {
|
fn description() -> Option<&'static str> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
|
None
|
||||||
pub trait ComponentPreview: Component {
|
}
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[distributed_slice]
|
#[distributed_slice]
|
||||||
pub static __ALL_COMPONENTS: [fn()] = [..];
|
pub static __ALL_COMPONENTS: [fn()] = [..];
|
||||||
|
|
||||||
#[distributed_slice]
|
|
||||||
pub static __ALL_PREVIEWS: [fn()] = [..];
|
|
||||||
|
|
||||||
pub static COMPONENT_DATA: LazyLock<RwLock<ComponentRegistry>> =
|
pub static COMPONENT_DATA: LazyLock<RwLock<ComponentRegistry>> =
|
||||||
LazyLock::new(|| RwLock::new(ComponentRegistry::new()));
|
LazyLock::new(|| RwLock::new(ComponentRegistry::new()));
|
||||||
|
|
||||||
pub struct ComponentRegistry {
|
pub struct ComponentRegistry {
|
||||||
components: Vec<(Option<ComponentScope>, &'static str, Option<&'static str>)>,
|
components: Vec<(
|
||||||
previews: HashMap<&'static str, fn(&mut Window, &mut App) -> AnyElement>,
|
ComponentScope,
|
||||||
|
// name
|
||||||
|
&'static str,
|
||||||
|
// sort name
|
||||||
|
&'static str,
|
||||||
|
// description
|
||||||
|
Option<&'static str>,
|
||||||
|
)>,
|
||||||
|
previews: HashMap<&'static str, fn(&mut Window, &mut App) -> Option<AnyElement>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentRegistry {
|
impl ComponentRegistry {
|
||||||
|
@ -47,30 +72,16 @@ impl ComponentRegistry {
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
let component_fns: Vec<_> = __ALL_COMPONENTS.iter().cloned().collect();
|
let component_fns: Vec<_> = __ALL_COMPONENTS.iter().cloned().collect();
|
||||||
let preview_fns: Vec<_> = __ALL_PREVIEWS.iter().cloned().collect();
|
|
||||||
|
|
||||||
for f in component_fns {
|
for f in component_fns {
|
||||||
f();
|
f();
|
||||||
}
|
}
|
||||||
for f in preview_fns {
|
|
||||||
f();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_component<T: Component>() {
|
pub fn register_component<T: Component>() {
|
||||||
let component_data = (T::scope(), T::name(), T::description());
|
let component_data = (T::scope(), T::name(), T::sort_name(), T::description());
|
||||||
COMPONENT_DATA.write().components.push(component_data);
|
let mut data = COMPONENT_DATA.write();
|
||||||
}
|
data.components.push(component_data);
|
||||||
|
data.previews.insert(T::name(), T::preview);
|
||||||
pub fn register_preview<T: ComponentPreview>() {
|
|
||||||
let preview_data = (
|
|
||||||
T::name(),
|
|
||||||
T::preview as fn(&mut Window, &mut App) -> AnyElement,
|
|
||||||
);
|
|
||||||
COMPONENT_DATA
|
|
||||||
.write()
|
|
||||||
.previews
|
|
||||||
.insert(preview_data.0, preview_data.1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -80,29 +91,41 @@ pub struct ComponentId(pub &'static str);
|
||||||
pub struct ComponentMetadata {
|
pub struct ComponentMetadata {
|
||||||
id: ComponentId,
|
id: ComponentId,
|
||||||
name: SharedString,
|
name: SharedString,
|
||||||
scope: Option<ComponentScope>,
|
sort_name: SharedString,
|
||||||
|
scope: ComponentScope,
|
||||||
description: Option<SharedString>,
|
description: Option<SharedString>,
|
||||||
preview: Option<fn(&mut Window, &mut App) -> AnyElement>,
|
preview: Option<fn(&mut Window, &mut App) -> Option<AnyElement>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentMetadata {
|
impl ComponentMetadata {
|
||||||
pub fn id(&self) -> ComponentId {
|
pub fn id(&self) -> ComponentId {
|
||||||
self.id.clone()
|
self.id.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> SharedString {
|
pub fn name(&self) -> SharedString {
|
||||||
self.name.clone()
|
self.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scope(&self) -> Option<ComponentScope> {
|
pub fn sort_name(&self) -> SharedString {
|
||||||
self.scope.clone()
|
self.sort_name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn scopeless_name(&self) -> SharedString {
|
||||||
|
self.name
|
||||||
|
.clone()
|
||||||
|
.split("::")
|
||||||
|
.last()
|
||||||
|
.unwrap_or(&self.name)
|
||||||
|
.to_string()
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scope(&self) -> ComponentScope {
|
||||||
|
self.scope.clone()
|
||||||
|
}
|
||||||
pub fn description(&self) -> Option<SharedString> {
|
pub fn description(&self) -> Option<SharedString> {
|
||||||
self.description.clone()
|
self.description.clone()
|
||||||
}
|
}
|
||||||
|
pub fn preview(&self) -> Option<fn(&mut Window, &mut App) -> Option<AnyElement>> {
|
||||||
pub fn preview(&self) -> Option<fn(&mut Window, &mut App) -> AnyElement> {
|
|
||||||
self.preview
|
self.preview
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,26 +136,18 @@ impl AllComponents {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
AllComponents(HashMap::default())
|
AllComponents(HashMap::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all components with previews
|
|
||||||
pub fn all_previews(&self) -> Vec<&ComponentMetadata> {
|
pub fn all_previews(&self) -> Vec<&ComponentMetadata> {
|
||||||
self.0.values().filter(|c| c.preview.is_some()).collect()
|
self.0.values().filter(|c| c.preview.is_some()).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all components with previews sorted by name
|
|
||||||
pub fn all_previews_sorted(&self) -> Vec<ComponentMetadata> {
|
pub fn all_previews_sorted(&self) -> Vec<ComponentMetadata> {
|
||||||
let mut previews: Vec<ComponentMetadata> =
|
let mut previews: Vec<ComponentMetadata> =
|
||||||
self.all_previews().into_iter().cloned().collect();
|
self.all_previews().into_iter().cloned().collect();
|
||||||
previews.sort_by_key(|a| a.name());
|
previews.sort_by_key(|a| a.name());
|
||||||
previews
|
previews
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all components
|
|
||||||
pub fn all(&self) -> Vec<&ComponentMetadata> {
|
pub fn all(&self) -> Vec<&ComponentMetadata> {
|
||||||
self.0.values().collect()
|
self.0.values().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all components sorted by name
|
|
||||||
pub fn all_sorted(&self) -> Vec<ComponentMetadata> {
|
pub fn all_sorted(&self) -> Vec<ComponentMetadata> {
|
||||||
let mut components: Vec<ComponentMetadata> = self.all().into_iter().cloned().collect();
|
let mut components: Vec<ComponentMetadata> = self.all().into_iter().cloned().collect();
|
||||||
components.sort_by_key(|a| a.name());
|
components.sort_by_key(|a| a.name());
|
||||||
|
@ -142,7 +157,6 @@ impl AllComponents {
|
||||||
|
|
||||||
impl Deref for AllComponents {
|
impl Deref for AllComponents {
|
||||||
type Target = HashMap<ComponentId, ComponentMetadata>;
|
type Target = HashMap<ComponentId, ComponentMetadata>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
@ -157,139 +171,127 @@ impl DerefMut for AllComponents {
|
||||||
pub fn components() -> AllComponents {
|
pub fn components() -> AllComponents {
|
||||||
let data = COMPONENT_DATA.read();
|
let data = COMPONENT_DATA.read();
|
||||||
let mut all_components = AllComponents::new();
|
let mut all_components = AllComponents::new();
|
||||||
|
for (scope, name, sort_name, description) in &data.components {
|
||||||
for (scope, name, description) in &data.components {
|
|
||||||
let preview = data.previews.get(name).cloned();
|
let preview = data.previews.get(name).cloned();
|
||||||
let component_name = SharedString::new_static(name);
|
let component_name = SharedString::new_static(name);
|
||||||
|
let sort_name = SharedString::new_static(sort_name);
|
||||||
let id = ComponentId(name);
|
let id = ComponentId(name);
|
||||||
all_components.insert(
|
all_components.insert(
|
||||||
id.clone(),
|
id.clone(),
|
||||||
ComponentMetadata {
|
ComponentMetadata {
|
||||||
id,
|
id,
|
||||||
name: component_name,
|
name: component_name,
|
||||||
|
sort_name,
|
||||||
scope: scope.clone(),
|
scope: scope.clone(),
|
||||||
description: description.map(Into::into),
|
description: description.map(Into::into),
|
||||||
preview,
|
preview,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
all_components
|
all_components
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum ComponentScope {
|
pub enum ComponentScope {
|
||||||
Layout,
|
|
||||||
Input,
|
|
||||||
Notification,
|
|
||||||
Editor,
|
|
||||||
Collaboration,
|
Collaboration,
|
||||||
|
DataDisplay,
|
||||||
|
Editor,
|
||||||
|
Images,
|
||||||
|
Input,
|
||||||
|
Layout,
|
||||||
|
Loading,
|
||||||
|
Navigation,
|
||||||
|
None,
|
||||||
|
Notification,
|
||||||
|
Overlays,
|
||||||
|
Status,
|
||||||
|
Typography,
|
||||||
VersionControl,
|
VersionControl,
|
||||||
Unknown(SharedString),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for ComponentScope {
|
impl Display for ComponentScope {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
ComponentScope::Layout => write!(f, "Layout"),
|
|
||||||
ComponentScope::Input => write!(f, "Input"),
|
|
||||||
ComponentScope::Notification => write!(f, "Notification"),
|
|
||||||
ComponentScope::Editor => write!(f, "Editor"),
|
|
||||||
ComponentScope::Collaboration => write!(f, "Collaboration"),
|
ComponentScope::Collaboration => write!(f, "Collaboration"),
|
||||||
|
ComponentScope::DataDisplay => write!(f, "Data Display"),
|
||||||
|
ComponentScope::Editor => write!(f, "Editor"),
|
||||||
|
ComponentScope::Images => write!(f, "Images & Icons"),
|
||||||
|
ComponentScope::Input => write!(f, "Forms & Input"),
|
||||||
|
ComponentScope::Layout => write!(f, "Layout & Structure"),
|
||||||
|
ComponentScope::Loading => write!(f, "Loading & Progress"),
|
||||||
|
ComponentScope::Navigation => write!(f, "Navigation"),
|
||||||
|
ComponentScope::None => write!(f, "Unsorted"),
|
||||||
|
ComponentScope::Notification => write!(f, "Notification"),
|
||||||
|
ComponentScope::Overlays => write!(f, "Overlays & Layering"),
|
||||||
|
ComponentScope::Status => write!(f, "Status"),
|
||||||
|
ComponentScope::Typography => write!(f, "Typography"),
|
||||||
ComponentScope::VersionControl => write!(f, "Version Control"),
|
ComponentScope::VersionControl => write!(f, "Version Control"),
|
||||||
ComponentScope::Unknown(name) => write!(f, "Unknown: {}", name),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for ComponentScope {
|
|
||||||
fn from(value: &str) -> Self {
|
|
||||||
match value {
|
|
||||||
"Layout" => ComponentScope::Layout,
|
|
||||||
"Input" => ComponentScope::Input,
|
|
||||||
"Notification" => ComponentScope::Notification,
|
|
||||||
"Editor" => ComponentScope::Editor,
|
|
||||||
"Collaboration" => ComponentScope::Collaboration,
|
|
||||||
"Version Control" | "VersionControl" => ComponentScope::VersionControl,
|
|
||||||
_ => ComponentScope::Unknown(SharedString::new(value)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<String> for ComponentScope {
|
|
||||||
fn from(value: String) -> Self {
|
|
||||||
match value.as_str() {
|
|
||||||
"Layout" => ComponentScope::Layout,
|
|
||||||
"Input" => ComponentScope::Input,
|
|
||||||
"Notification" => ComponentScope::Notification,
|
|
||||||
"Editor" => ComponentScope::Editor,
|
|
||||||
"Collaboration" => ComponentScope::Collaboration,
|
|
||||||
"Version Control" | "VersionControl" => ComponentScope::VersionControl,
|
|
||||||
_ => ComponentScope::Unknown(SharedString::new(value)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Which side of the preview to show labels on
|
|
||||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum ExampleLabelSide {
|
|
||||||
/// Left side
|
|
||||||
Left,
|
|
||||||
/// Right side
|
|
||||||
Right,
|
|
||||||
/// Top side
|
|
||||||
#[default]
|
|
||||||
Top,
|
|
||||||
/// Bottom side
|
|
||||||
Bottom,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A single example of a component.
|
/// A single example of a component.
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
pub struct ComponentExample {
|
pub struct ComponentExample {
|
||||||
variant_name: SharedString,
|
pub variant_name: SharedString,
|
||||||
element: AnyElement,
|
pub description: Option<SharedString>,
|
||||||
label_side: ExampleLabelSide,
|
pub element: AnyElement,
|
||||||
grow: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderOnce for ComponentExample {
|
impl RenderOnce for ComponentExample {
|
||||||
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
let base = div().flex();
|
div()
|
||||||
|
.w_full()
|
||||||
let base = match self.label_side {
|
.flex()
|
||||||
ExampleLabelSide::Right => base.flex_row(),
|
.flex_col()
|
||||||
ExampleLabelSide::Left => base.flex_row_reverse(),
|
.gap_3()
|
||||||
ExampleLabelSide::Bottom => base.flex_col(),
|
.child(
|
||||||
ExampleLabelSide::Top => base.flex_col_reverse(),
|
div()
|
||||||
};
|
.child(self.variant_name.clone())
|
||||||
|
.text_size(rems(1.25))
|
||||||
base.gap_2()
|
.text_color(cx.theme().colors().text),
|
||||||
.p_2()
|
)
|
||||||
.text_size(px(10.))
|
.when_some(self.description, |this, description| {
|
||||||
.text_color(cx.theme().colors().text_muted)
|
this.child(
|
||||||
.when(self.grow, |this| this.flex_1())
|
div()
|
||||||
.when(!self.grow, |this| this.flex_none())
|
.text_size(rems(0.9375))
|
||||||
.child(self.element)
|
.text_color(cx.theme().colors().text_muted)
|
||||||
.child(self.variant_name)
|
.child(description.clone()),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.w_full()
|
||||||
|
.rounded_xl()
|
||||||
|
.min_h(px(100.))
|
||||||
|
.justify_center()
|
||||||
|
.p_8()
|
||||||
|
.border_1()
|
||||||
|
.border_color(cx.theme().colors().border)
|
||||||
|
.bg(pattern_slash(
|
||||||
|
cx.theme().colors().surface_background.opacity(0.5),
|
||||||
|
24.0,
|
||||||
|
24.0,
|
||||||
|
))
|
||||||
|
.shadow_sm()
|
||||||
|
.child(self.element),
|
||||||
|
)
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentExample {
|
impl ComponentExample {
|
||||||
/// Create a new example with the given variant name and example value.
|
|
||||||
pub fn new(variant_name: impl Into<SharedString>, element: AnyElement) -> Self {
|
pub fn new(variant_name: impl Into<SharedString>, element: AnyElement) -> Self {
|
||||||
Self {
|
Self {
|
||||||
variant_name: variant_name.into(),
|
variant_name: variant_name.into(),
|
||||||
element,
|
element,
|
||||||
label_side: ExampleLabelSide::default(),
|
description: None,
|
||||||
grow: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the example to grow to fill the available horizontal space.
|
pub fn description(mut self, description: impl Into<SharedString>) -> Self {
|
||||||
pub fn grow(mut self) -> Self {
|
self.description = Some(description.into());
|
||||||
self.grow = true;
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -309,7 +311,7 @@ impl RenderOnce for ComponentExampleGroup {
|
||||||
.flex_col()
|
.flex_col()
|
||||||
.text_sm()
|
.text_sm()
|
||||||
.text_color(cx.theme().colors().text_muted)
|
.text_color(cx.theme().colors().text_muted)
|
||||||
.when(self.grow, |this| this.w_full().flex_1())
|
.w_full()
|
||||||
.when_some(self.title, |this, title| {
|
.when_some(self.title, |this, title| {
|
||||||
this.gap_4().child(
|
this.gap_4().child(
|
||||||
div()
|
div()
|
||||||
|
@ -336,7 +338,7 @@ impl RenderOnce for ComponentExampleGroup {
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
.when(self.vertical, |this| this.flex_col())
|
.flex_col()
|
||||||
.items_start()
|
.items_start()
|
||||||
.w_full()
|
.w_full()
|
||||||
.gap_6()
|
.gap_6()
|
||||||
|
@ -348,7 +350,6 @@ impl RenderOnce for ComponentExampleGroup {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentExampleGroup {
|
impl ComponentExampleGroup {
|
||||||
/// Create a new group of examples with the given title.
|
|
||||||
pub fn new(examples: Vec<ComponentExample>) -> Self {
|
pub fn new(examples: Vec<ComponentExample>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
title: None,
|
title: None,
|
||||||
|
@ -357,8 +358,6 @@ impl ComponentExampleGroup {
|
||||||
vertical: false,
|
vertical: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new group of examples with the given title.
|
|
||||||
pub fn with_title(title: impl Into<SharedString>, examples: Vec<ComponentExample>) -> Self {
|
pub fn with_title(title: impl Into<SharedString>, examples: Vec<ComponentExample>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
title: Some(title.into()),
|
title: Some(title.into()),
|
||||||
|
@ -367,21 +366,16 @@ impl ComponentExampleGroup {
|
||||||
vertical: false,
|
vertical: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the group to grow to fill the available horizontal space.
|
|
||||||
pub fn grow(mut self) -> Self {
|
pub fn grow(mut self) -> Self {
|
||||||
self.grow = true;
|
self.grow = true;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lay the group out vertically.
|
|
||||||
pub fn vertical(mut self) -> Self {
|
pub fn vertical(mut self) -> Self {
|
||||||
self.vertical = true;
|
self.vertical = true;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a single example
|
|
||||||
pub fn single_example(
|
pub fn single_example(
|
||||||
variant_name: impl Into<SharedString>,
|
variant_name: impl Into<SharedString>,
|
||||||
example: AnyElement,
|
example: AnyElement,
|
||||||
|
@ -389,12 +383,10 @@ pub fn single_example(
|
||||||
ComponentExample::new(variant_name, example)
|
ComponentExample::new(variant_name, example)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a group of examples without a title
|
|
||||||
pub fn example_group(examples: Vec<ComponentExample>) -> ComponentExampleGroup {
|
pub fn example_group(examples: Vec<ComponentExample>) -> ComponentExampleGroup {
|
||||||
ComponentExampleGroup::new(examples)
|
ComponentExampleGroup::new(examples)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a group of examples with a title
|
|
||||||
pub fn example_group_with_title(
|
pub fn example_group_with_title(
|
||||||
title: impl Into<SharedString>,
|
title: impl Into<SharedString>,
|
||||||
examples: Vec<ComponentExample>,
|
examples: Vec<ComponentExample>,
|
||||||
|
|
|
@ -43,6 +43,7 @@ pub fn init(app_state: Arc<AppState>, cx: &mut App) {
|
||||||
language_registry,
|
language_registry,
|
||||||
user_store,
|
user_store,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
@ -106,10 +107,12 @@ impl ComponentPreview {
|
||||||
language_registry: Arc<LanguageRegistry>,
|
language_registry: Arc<LanguageRegistry>,
|
||||||
user_store: Entity<UserStore>,
|
user_store: Entity<UserStore>,
|
||||||
selected_index: impl Into<Option<usize>>,
|
selected_index: impl Into<Option<usize>>,
|
||||||
|
active_page: Option<PreviewPage>,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let sorted_components = components().all_sorted();
|
let sorted_components = components().all_sorted();
|
||||||
let selected_index = selected_index.into().unwrap_or(0);
|
let selected_index = selected_index.into().unwrap_or(0);
|
||||||
|
let active_page = active_page.unwrap_or(PreviewPage::AllComponents);
|
||||||
|
|
||||||
let component_list = ListState::new(
|
let component_list = ListState::new(
|
||||||
sorted_components.len(),
|
sorted_components.len(),
|
||||||
|
@ -135,7 +138,7 @@ impl ComponentPreview {
|
||||||
language_registry,
|
language_registry,
|
||||||
user_store,
|
user_store,
|
||||||
workspace,
|
workspace,
|
||||||
active_page: PreviewPage::AllComponents,
|
active_page,
|
||||||
component_map: components().0,
|
component_map: components().0,
|
||||||
components: sorted_components,
|
components: sorted_components,
|
||||||
component_list,
|
component_list,
|
||||||
|
@ -169,8 +172,7 @@ impl ComponentPreview {
|
||||||
fn scope_ordered_entries(&self) -> Vec<PreviewEntry> {
|
fn scope_ordered_entries(&self) -> Vec<PreviewEntry> {
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
let mut scope_groups: HashMap<Option<ComponentScope>, Vec<ComponentMetadata>> =
|
let mut scope_groups: HashMap<ComponentScope, Vec<ComponentMetadata>> = HashMap::default();
|
||||||
HashMap::default();
|
|
||||||
|
|
||||||
for component in &self.components {
|
for component in &self.components {
|
||||||
scope_groups
|
scope_groups
|
||||||
|
@ -192,6 +194,7 @@ impl ComponentPreview {
|
||||||
ComponentScope::Notification,
|
ComponentScope::Notification,
|
||||||
ComponentScope::Collaboration,
|
ComponentScope::Collaboration,
|
||||||
ComponentScope::VersionControl,
|
ComponentScope::VersionControl,
|
||||||
|
ComponentScope::None,
|
||||||
];
|
];
|
||||||
|
|
||||||
// Always show all components first
|
// Always show all components first
|
||||||
|
@ -199,38 +202,27 @@ impl ComponentPreview {
|
||||||
entries.push(PreviewEntry::Separator);
|
entries.push(PreviewEntry::Separator);
|
||||||
|
|
||||||
for scope in known_scopes.iter() {
|
for scope in known_scopes.iter() {
|
||||||
let scope_key = Some(scope.clone());
|
if let Some(components) = scope_groups.remove(scope) {
|
||||||
if let Some(components) = scope_groups.remove(&scope_key) {
|
|
||||||
if !components.is_empty() {
|
if !components.is_empty() {
|
||||||
entries.push(PreviewEntry::SectionHeader(scope.to_string().into()));
|
entries.push(PreviewEntry::SectionHeader(scope.to_string().into()));
|
||||||
|
let mut sorted_components = components;
|
||||||
|
sorted_components.sort_by_key(|component| component.sort_name());
|
||||||
|
|
||||||
for component in components {
|
for component in sorted_components {
|
||||||
entries.push(PreviewEntry::Component(component));
|
entries.push(PreviewEntry::Component(component));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (scope, components) in &scope_groups {
|
if let Some(components) = scope_groups.get(&ComponentScope::None) {
|
||||||
if let Some(ComponentScope::Unknown(_)) = scope {
|
|
||||||
if !components.is_empty() {
|
|
||||||
if let Some(scope_value) = scope {
|
|
||||||
entries.push(PreviewEntry::SectionHeader(scope_value.to_string().into()));
|
|
||||||
}
|
|
||||||
|
|
||||||
for component in components {
|
|
||||||
entries.push(PreviewEntry::Component(component.clone()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(components) = scope_groups.get(&None) {
|
|
||||||
if !components.is_empty() {
|
if !components.is_empty() {
|
||||||
entries.push(PreviewEntry::Separator);
|
entries.push(PreviewEntry::Separator);
|
||||||
entries.push(PreviewEntry::SectionHeader("Uncategorized".into()));
|
entries.push(PreviewEntry::SectionHeader("Uncategorized".into()));
|
||||||
|
let mut sorted_components = components.clone();
|
||||||
|
sorted_components.sort_by_key(|c| c.sort_name());
|
||||||
|
|
||||||
for component in components {
|
for component in sorted_components {
|
||||||
entries.push(PreviewEntry::Component(component.clone()));
|
entries.push(PreviewEntry::Component(component.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,7 +242,10 @@ impl ComponentPreview {
|
||||||
let id = component_metadata.id();
|
let id = component_metadata.id();
|
||||||
let selected = self.active_page == PreviewPage::Component(id.clone());
|
let selected = self.active_page == PreviewPage::Component(id.clone());
|
||||||
ListItem::new(ix)
|
ListItem::new(ix)
|
||||||
.child(Label::new(component_metadata.name().clone()).color(Color::Default))
|
.child(
|
||||||
|
Label::new(component_metadata.scopeless_name().clone())
|
||||||
|
.color(Color::Default),
|
||||||
|
)
|
||||||
.selectable(true)
|
.selectable(true)
|
||||||
.toggle_state(selected)
|
.toggle_state(selected)
|
||||||
.inset(true)
|
.inset(true)
|
||||||
|
@ -333,7 +328,7 @@ impl ComponentPreview {
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> impl IntoElement {
|
) -> impl IntoElement {
|
||||||
let name = component.name();
|
let name = component.scopeless_name();
|
||||||
let scope = component.scope();
|
let scope = component.scope();
|
||||||
|
|
||||||
let description = component.description();
|
let description = component.description();
|
||||||
|
@ -354,13 +349,12 @@ impl ComponentPreview {
|
||||||
v_flex()
|
v_flex()
|
||||||
.gap_1()
|
.gap_1()
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex().gap_1().text_xl().child(div().child(name)).when(
|
||||||
.gap_1()
|
!matches!(scope, ComponentScope::None),
|
||||||
.text_xl()
|
|this| {
|
||||||
.child(div().child(name))
|
|
||||||
.when_some(scope, |this, scope| {
|
|
||||||
this.child(div().opacity(0.5).child(format!("({})", scope)))
|
this.child(div().opacity(0.5).child(format!("({})", scope)))
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.when_some(description, |this, description| {
|
.when_some(description, |this, description| {
|
||||||
this.child(
|
this.child(
|
||||||
|
@ -373,7 +367,7 @@ impl ComponentPreview {
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.when_some(component.preview(), |this, preview| {
|
.when_some(component.preview(), |this, preview| {
|
||||||
this.child(preview(window, cx))
|
this.children(preview(window, cx))
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
|
@ -395,17 +389,16 @@ impl ComponentPreview {
|
||||||
fn render_component_page(
|
fn render_component_page(
|
||||||
&mut self,
|
&mut self,
|
||||||
component_id: &ComponentId,
|
component_id: &ComponentId,
|
||||||
window: &mut Window,
|
_window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
_cx: &mut Context<Self>,
|
||||||
) -> impl IntoElement {
|
) -> impl IntoElement {
|
||||||
let component = self.component_map.get(&component_id);
|
let component = self.component_map.get(&component_id);
|
||||||
|
|
||||||
if let Some(component) = component {
|
if let Some(component) = component {
|
||||||
v_flex()
|
v_flex()
|
||||||
.w_full()
|
.id("render-component-page")
|
||||||
.flex_initial()
|
.size_full()
|
||||||
.min_h_full()
|
.child(ComponentPreviewPage::new(component.clone()))
|
||||||
.child(self.render_preview(component, window, cx))
|
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
} else {
|
} else {
|
||||||
v_flex()
|
v_flex()
|
||||||
|
@ -445,10 +438,11 @@ impl Render for ComponentPreview {
|
||||||
.overflow_hidden()
|
.overflow_hidden()
|
||||||
.size_full()
|
.size_full()
|
||||||
.track_focus(&self.focus_handle)
|
.track_focus(&self.focus_handle)
|
||||||
.px_2()
|
|
||||||
.bg(cx.theme().colors().editor_background)
|
.bg(cx.theme().colors().editor_background)
|
||||||
.child(
|
.child(
|
||||||
v_flex()
|
v_flex()
|
||||||
|
.border_r_1()
|
||||||
|
.border_color(cx.theme().colors().border)
|
||||||
.h_full()
|
.h_full()
|
||||||
.child(
|
.child(
|
||||||
uniform_list(
|
uniform_list(
|
||||||
|
@ -465,6 +459,7 @@ impl Render for ComponentPreview {
|
||||||
)
|
)
|
||||||
.track_scroll(self.nav_scroll_handle.clone())
|
.track_scroll(self.nav_scroll_handle.clone())
|
||||||
.pt_4()
|
.pt_4()
|
||||||
|
.px_4()
|
||||||
.w(px(240.))
|
.w(px(240.))
|
||||||
.h_full()
|
.h_full()
|
||||||
.flex_1(),
|
.flex_1(),
|
||||||
|
@ -527,6 +522,7 @@ impl Item for ComponentPreview {
|
||||||
let user_store = self.user_store.clone();
|
let user_store = self.user_store.clone();
|
||||||
let weak_workspace = self.workspace.clone();
|
let weak_workspace = self.workspace.clone();
|
||||||
let selected_index = self.cursor_index;
|
let selected_index = self.cursor_index;
|
||||||
|
let active_page = self.active_page.clone();
|
||||||
|
|
||||||
Some(cx.new(|cx| {
|
Some(cx.new(|cx| {
|
||||||
Self::new(
|
Self::new(
|
||||||
|
@ -534,6 +530,7 @@ impl Item for ComponentPreview {
|
||||||
language_registry,
|
language_registry,
|
||||||
user_store,
|
user_store,
|
||||||
selected_index,
|
selected_index,
|
||||||
|
Some(active_page),
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
}))
|
}))
|
||||||
|
@ -566,7 +563,14 @@ impl SerializableItem for ComponentPreview {
|
||||||
let weak_workspace = workspace.clone();
|
let weak_workspace = workspace.clone();
|
||||||
cx.update(|_, cx| {
|
cx.update(|_, cx| {
|
||||||
Ok(cx.new(|cx| {
|
Ok(cx.new(|cx| {
|
||||||
ComponentPreview::new(weak_workspace, language_registry, user_store, None, cx)
|
ComponentPreview::new(
|
||||||
|
weak_workspace,
|
||||||
|
language_registry,
|
||||||
|
user_store,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
}))
|
}))
|
||||||
})?
|
})?
|
||||||
})
|
})
|
||||||
|
@ -600,3 +604,76 @@ impl SerializableItem for ComponentPreview {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(IntoElement)]
|
||||||
|
pub struct ComponentPreviewPage {
|
||||||
|
// languages: Arc<LanguageRegistry>,
|
||||||
|
component: ComponentMetadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ComponentPreviewPage {
|
||||||
|
pub fn new(
|
||||||
|
component: ComponentMetadata,
|
||||||
|
// languages: Arc<LanguageRegistry>
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
// languages,
|
||||||
|
component,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_header(&self, _: &Window, cx: &App) -> impl IntoElement {
|
||||||
|
v_flex()
|
||||||
|
.px_12()
|
||||||
|
.pt_16()
|
||||||
|
.pb_12()
|
||||||
|
.gap_6()
|
||||||
|
.bg(cx.theme().colors().surface_background)
|
||||||
|
.border_b_1()
|
||||||
|
.border_color(cx.theme().colors().border)
|
||||||
|
.child(
|
||||||
|
v_flex()
|
||||||
|
.gap_0p5()
|
||||||
|
.child(
|
||||||
|
Label::new(self.component.scope().to_string())
|
||||||
|
.size(LabelSize::Small)
|
||||||
|
.color(Color::Muted),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Headline::new(self.component.scopeless_name()).size(HeadlineSize::XLarge),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.when_some(self.component.description(), |this, description| {
|
||||||
|
this.child(div().text_sm().child(description))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_preview(&self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
|
v_flex()
|
||||||
|
.flex_1()
|
||||||
|
.px_12()
|
||||||
|
.py_6()
|
||||||
|
.bg(cx.theme().colors().editor_background)
|
||||||
|
.child(if let Some(preview) = self.component.preview() {
|
||||||
|
preview(window, cx).unwrap_or_else(|| {
|
||||||
|
div()
|
||||||
|
.child("Failed to load preview. This path should be unreachable")
|
||||||
|
.into_any_element()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
div().child("No preview available").into_any_element()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderOnce for ComponentPreviewPage {
|
||||||
|
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
|
v_flex()
|
||||||
|
.id("component-preview-page")
|
||||||
|
.overflow_y_scroll()
|
||||||
|
.overflow_x_hidden()
|
||||||
|
.w_full()
|
||||||
|
.child(self.render_header(window, cx))
|
||||||
|
.child(self.render_preview(window, cx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3953,8 +3953,7 @@ impl Render for GitPanelMessageTooltip {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(IntoElement, IntoComponent)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
#[component(scope = "Version Control")]
|
|
||||||
pub struct PanelRepoFooter {
|
pub struct PanelRepoFooter {
|
||||||
active_repository: SharedString,
|
active_repository: SharedString,
|
||||||
branch: Option<Branch>,
|
branch: Option<Branch>,
|
||||||
|
@ -4134,8 +4133,12 @@ impl RenderOnce for PanelRepoFooter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentPreview for PanelRepoFooter {
|
impl Component for PanelRepoFooter {
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::VersionControl
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
let unknown_upstream = None;
|
let unknown_upstream = None;
|
||||||
let no_remote_upstream = Some(UpstreamTracking::Gone);
|
let no_remote_upstream = Some(UpstreamTracking::Gone);
|
||||||
let ahead_of_upstream = Some(
|
let ahead_of_upstream = Some(
|
||||||
|
@ -4207,192 +4210,180 @@ impl ComponentPreview for PanelRepoFooter {
|
||||||
}
|
}
|
||||||
|
|
||||||
let example_width = px(340.);
|
let example_width = px(340.);
|
||||||
|
Some(
|
||||||
v_flex()
|
v_flex()
|
||||||
.gap_6()
|
.gap_6()
|
||||||
.w_full()
|
.w_full()
|
||||||
.flex_none()
|
.flex_none()
|
||||||
.children(vec![
|
.children(vec![
|
||||||
example_group_with_title(
|
example_group_with_title(
|
||||||
"Action Button States",
|
"Action Button States",
|
||||||
vec![
|
vec![
|
||||||
single_example(
|
single_example(
|
||||||
"No Branch",
|
"No Branch",
|
||||||
div()
|
div()
|
||||||
.w(example_width)
|
.w(example_width)
|
||||||
.overflow_hidden()
|
.overflow_hidden()
|
||||||
.child(PanelRepoFooter::new_preview(
|
.child(PanelRepoFooter::new_preview(
|
||||||
active_repository(1).clone(),
|
active_repository(1).clone(),
|
||||||
None,
|
None,
|
||||||
))
|
))
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
)
|
),
|
||||||
.grow(),
|
single_example(
|
||||||
single_example(
|
"Remote status unknown",
|
||||||
"Remote status unknown",
|
div()
|
||||||
div()
|
.w(example_width)
|
||||||
.w(example_width)
|
.overflow_hidden()
|
||||||
.overflow_hidden()
|
.child(PanelRepoFooter::new_preview(
|
||||||
.child(PanelRepoFooter::new_preview(
|
active_repository(2).clone(),
|
||||||
active_repository(2).clone(),
|
Some(branch(unknown_upstream)),
|
||||||
Some(branch(unknown_upstream)),
|
))
|
||||||
))
|
.into_any_element(),
|
||||||
.into_any_element(),
|
),
|
||||||
)
|
single_example(
|
||||||
.grow(),
|
"No Remote Upstream",
|
||||||
single_example(
|
div()
|
||||||
"No Remote Upstream",
|
.w(example_width)
|
||||||
div()
|
.overflow_hidden()
|
||||||
.w(example_width)
|
.child(PanelRepoFooter::new_preview(
|
||||||
.overflow_hidden()
|
active_repository(3).clone(),
|
||||||
.child(PanelRepoFooter::new_preview(
|
Some(branch(no_remote_upstream)),
|
||||||
active_repository(3).clone(),
|
))
|
||||||
Some(branch(no_remote_upstream)),
|
.into_any_element(),
|
||||||
))
|
),
|
||||||
.into_any_element(),
|
single_example(
|
||||||
)
|
"Not Ahead or Behind",
|
||||||
.grow(),
|
div()
|
||||||
single_example(
|
.w(example_width)
|
||||||
"Not Ahead or Behind",
|
.overflow_hidden()
|
||||||
div()
|
.child(PanelRepoFooter::new_preview(
|
||||||
.w(example_width)
|
active_repository(4).clone(),
|
||||||
.overflow_hidden()
|
Some(branch(not_ahead_or_behind_upstream)),
|
||||||
.child(PanelRepoFooter::new_preview(
|
))
|
||||||
active_repository(4).clone(),
|
.into_any_element(),
|
||||||
Some(branch(not_ahead_or_behind_upstream)),
|
),
|
||||||
))
|
single_example(
|
||||||
.into_any_element(),
|
"Behind remote",
|
||||||
)
|
div()
|
||||||
.grow(),
|
.w(example_width)
|
||||||
single_example(
|
.overflow_hidden()
|
||||||
"Behind remote",
|
.child(PanelRepoFooter::new_preview(
|
||||||
div()
|
active_repository(5).clone(),
|
||||||
.w(example_width)
|
Some(branch(behind_upstream)),
|
||||||
.overflow_hidden()
|
))
|
||||||
.child(PanelRepoFooter::new_preview(
|
.into_any_element(),
|
||||||
active_repository(5).clone(),
|
),
|
||||||
Some(branch(behind_upstream)),
|
single_example(
|
||||||
))
|
"Ahead of remote",
|
||||||
.into_any_element(),
|
div()
|
||||||
)
|
.w(example_width)
|
||||||
.grow(),
|
.overflow_hidden()
|
||||||
single_example(
|
.child(PanelRepoFooter::new_preview(
|
||||||
"Ahead of remote",
|
active_repository(6).clone(),
|
||||||
div()
|
Some(branch(ahead_of_upstream)),
|
||||||
.w(example_width)
|
))
|
||||||
.overflow_hidden()
|
.into_any_element(),
|
||||||
.child(PanelRepoFooter::new_preview(
|
),
|
||||||
active_repository(6).clone(),
|
single_example(
|
||||||
Some(branch(ahead_of_upstream)),
|
"Ahead and behind remote",
|
||||||
))
|
div()
|
||||||
.into_any_element(),
|
.w(example_width)
|
||||||
)
|
.overflow_hidden()
|
||||||
.grow(),
|
.child(PanelRepoFooter::new_preview(
|
||||||
single_example(
|
active_repository(7).clone(),
|
||||||
"Ahead and behind remote",
|
Some(branch(ahead_and_behind_upstream)),
|
||||||
div()
|
))
|
||||||
.w(example_width)
|
.into_any_element(),
|
||||||
.overflow_hidden()
|
),
|
||||||
.child(PanelRepoFooter::new_preview(
|
],
|
||||||
active_repository(7).clone(),
|
)
|
||||||
Some(branch(ahead_and_behind_upstream)),
|
.grow()
|
||||||
))
|
.vertical(),
|
||||||
.into_any_element(),
|
])
|
||||||
)
|
.children(vec![
|
||||||
.grow(),
|
example_group_with_title(
|
||||||
],
|
"Labels",
|
||||||
)
|
vec![
|
||||||
.grow()
|
single_example(
|
||||||
.vertical(),
|
"Short Branch & Repo",
|
||||||
])
|
div()
|
||||||
.children(vec![
|
.w(example_width)
|
||||||
example_group_with_title(
|
.overflow_hidden()
|
||||||
"Labels",
|
.child(PanelRepoFooter::new_preview(
|
||||||
vec![
|
SharedString::from("zed"),
|
||||||
single_example(
|
Some(custom("main", behind_upstream)),
|
||||||
"Short Branch & Repo",
|
))
|
||||||
div()
|
.into_any_element(),
|
||||||
.w(example_width)
|
),
|
||||||
.overflow_hidden()
|
single_example(
|
||||||
.child(PanelRepoFooter::new_preview(
|
"Long Branch",
|
||||||
SharedString::from("zed"),
|
div()
|
||||||
Some(custom("main", behind_upstream)),
|
.w(example_width)
|
||||||
))
|
.overflow_hidden()
|
||||||
.into_any_element(),
|
.child(PanelRepoFooter::new_preview(
|
||||||
)
|
SharedString::from("zed"),
|
||||||
.grow(),
|
Some(custom(
|
||||||
single_example(
|
"redesign-and-update-git-ui-list-entry-style",
|
||||||
"Long Branch",
|
behind_upstream,
|
||||||
div()
|
)),
|
||||||
.w(example_width)
|
))
|
||||||
.overflow_hidden()
|
.into_any_element(),
|
||||||
.child(PanelRepoFooter::new_preview(
|
),
|
||||||
SharedString::from("zed"),
|
single_example(
|
||||||
Some(custom(
|
"Long Repo",
|
||||||
"redesign-and-update-git-ui-list-entry-style",
|
div()
|
||||||
behind_upstream,
|
.w(example_width)
|
||||||
)),
|
.overflow_hidden()
|
||||||
))
|
.child(PanelRepoFooter::new_preview(
|
||||||
.into_any_element(),
|
SharedString::from("zed-industries-community-examples"),
|
||||||
)
|
Some(custom("gpui", ahead_of_upstream)),
|
||||||
.grow(),
|
))
|
||||||
single_example(
|
.into_any_element(),
|
||||||
"Long Repo",
|
),
|
||||||
div()
|
single_example(
|
||||||
.w(example_width)
|
"Long Repo & Branch",
|
||||||
.overflow_hidden()
|
div()
|
||||||
.child(PanelRepoFooter::new_preview(
|
.w(example_width)
|
||||||
SharedString::from("zed-industries-community-examples"),
|
.overflow_hidden()
|
||||||
Some(custom("gpui", ahead_of_upstream)),
|
.child(PanelRepoFooter::new_preview(
|
||||||
))
|
SharedString::from("zed-industries-community-examples"),
|
||||||
.into_any_element(),
|
Some(custom(
|
||||||
)
|
"redesign-and-update-git-ui-list-entry-style",
|
||||||
.grow(),
|
behind_upstream,
|
||||||
single_example(
|
)),
|
||||||
"Long Repo & Branch",
|
))
|
||||||
div()
|
.into_any_element(),
|
||||||
.w(example_width)
|
),
|
||||||
.overflow_hidden()
|
single_example(
|
||||||
.child(PanelRepoFooter::new_preview(
|
"Uppercase Repo",
|
||||||
SharedString::from("zed-industries-community-examples"),
|
div()
|
||||||
Some(custom(
|
.w(example_width)
|
||||||
"redesign-and-update-git-ui-list-entry-style",
|
.overflow_hidden()
|
||||||
behind_upstream,
|
.child(PanelRepoFooter::new_preview(
|
||||||
)),
|
SharedString::from("LICENSES"),
|
||||||
))
|
Some(custom("main", ahead_of_upstream)),
|
||||||
.into_any_element(),
|
))
|
||||||
)
|
.into_any_element(),
|
||||||
.grow(),
|
),
|
||||||
single_example(
|
single_example(
|
||||||
"Uppercase Repo",
|
"Uppercase Branch",
|
||||||
div()
|
div()
|
||||||
.w(example_width)
|
.w(example_width)
|
||||||
.overflow_hidden()
|
.overflow_hidden()
|
||||||
.child(PanelRepoFooter::new_preview(
|
.child(PanelRepoFooter::new_preview(
|
||||||
SharedString::from("LICENSES"),
|
SharedString::from("zed"),
|
||||||
Some(custom("main", ahead_of_upstream)),
|
Some(custom("update-README", behind_upstream)),
|
||||||
))
|
))
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
)
|
),
|
||||||
.grow(),
|
],
|
||||||
single_example(
|
)
|
||||||
"Uppercase Branch",
|
.grow()
|
||||||
div()
|
.vertical(),
|
||||||
.w(example_width)
|
])
|
||||||
.overflow_hidden()
|
.into_any_element(),
|
||||||
.child(PanelRepoFooter::new_preview(
|
)
|
||||||
SharedString::from("zed"),
|
|
||||||
Some(custom("update-README", behind_upstream)),
|
|
||||||
))
|
|
||||||
.into_any_element(),
|
|
||||||
)
|
|
||||||
.grow(),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.grow()
|
|
||||||
.vertical(),
|
|
||||||
])
|
|
||||||
.into_any_element()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -441,8 +441,8 @@ mod remote_button {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(IntoElement, IntoComponent)]
|
/// A visual representation of a file's Git status.
|
||||||
#[component(scope = "Version Control")]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub struct GitStatusIcon {
|
pub struct GitStatusIcon {
|
||||||
status: FileStatus,
|
status: FileStatus,
|
||||||
}
|
}
|
||||||
|
@ -484,8 +484,12 @@ impl RenderOnce for GitStatusIcon {
|
||||||
}
|
}
|
||||||
|
|
||||||
// View this component preview using `workspace: open component-preview`
|
// View this component preview using `workspace: open component-preview`
|
||||||
impl ComponentPreview for GitStatusIcon {
|
impl Component for GitStatusIcon {
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::VersionControl
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
fn tracked_file_status(code: StatusCode) -> FileStatus {
|
fn tracked_file_status(code: StatusCode) -> FileStatus {
|
||||||
FileStatus::Tracked(git::status::TrackedStatus {
|
FileStatus::Tracked(git::status::TrackedStatus {
|
||||||
index_status: code,
|
index_status: code,
|
||||||
|
@ -502,17 +506,19 @@ impl ComponentPreview for GitStatusIcon {
|
||||||
}
|
}
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
v_flex()
|
Some(
|
||||||
.gap_6()
|
v_flex()
|
||||||
.children(vec![example_group(vec![
|
.gap_6()
|
||||||
single_example("Modified", GitStatusIcon::new(modified).into_any_element()),
|
.children(vec![example_group(vec![
|
||||||
single_example("Added", GitStatusIcon::new(added).into_any_element()),
|
single_example("Modified", GitStatusIcon::new(modified).into_any_element()),
|
||||||
single_example("Deleted", GitStatusIcon::new(deleted).into_any_element()),
|
single_example("Added", GitStatusIcon::new(added).into_any_element()),
|
||||||
single_example(
|
single_example("Deleted", GitStatusIcon::new(deleted).into_any_element()),
|
||||||
"Conflicted",
|
single_example(
|
||||||
GitStatusIcon::new(conflict).into_any_element(),
|
"Conflicted",
|
||||||
),
|
GitStatusIcon::new(conflict).into_any_element(),
|
||||||
])])
|
),
|
||||||
.into_any_element()
|
])])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1005,8 +1005,7 @@ impl Render for ProjectDiffToolbar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(IntoElement, IntoComponent)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
#[component(scope = "Version Control")]
|
|
||||||
pub struct ProjectDiffEmptyState {
|
pub struct ProjectDiffEmptyState {
|
||||||
pub no_repo: bool,
|
pub no_repo: bool,
|
||||||
pub can_push_and_pull: bool,
|
pub can_push_and_pull: bool,
|
||||||
|
@ -1178,8 +1177,12 @@ mod preview {
|
||||||
use super::ProjectDiffEmptyState;
|
use super::ProjectDiffEmptyState;
|
||||||
|
|
||||||
// View this component preview using `workspace: open component-preview`
|
// View this component preview using `workspace: open component-preview`
|
||||||
impl ComponentPreview for ProjectDiffEmptyState {
|
impl Component for ProjectDiffEmptyState {
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::VersionControl
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
let unknown_upstream: Option<UpstreamTracking> = None;
|
let unknown_upstream: Option<UpstreamTracking> = None;
|
||||||
let ahead_of_upstream: Option<UpstreamTracking> = Some(
|
let ahead_of_upstream: Option<UpstreamTracking> = Some(
|
||||||
UpstreamTrackingStatus {
|
UpstreamTrackingStatus {
|
||||||
|
@ -1244,46 +1247,48 @@ mod preview {
|
||||||
|
|
||||||
let (width, height) = (px(480.), px(320.));
|
let (width, height) = (px(480.), px(320.));
|
||||||
|
|
||||||
v_flex()
|
Some(
|
||||||
.gap_6()
|
v_flex()
|
||||||
.children(vec![
|
.gap_6()
|
||||||
example_group(vec![
|
.children(vec![
|
||||||
single_example(
|
example_group(vec![
|
||||||
"No Repo",
|
single_example(
|
||||||
div()
|
"No Repo",
|
||||||
.w(width)
|
div()
|
||||||
.h(height)
|
.w(width)
|
||||||
.child(no_repo_state)
|
.h(height)
|
||||||
.into_any_element(),
|
.child(no_repo_state)
|
||||||
),
|
.into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"No Changes",
|
single_example(
|
||||||
div()
|
"No Changes",
|
||||||
.w(width)
|
div()
|
||||||
.h(height)
|
.w(width)
|
||||||
.child(no_changes_state)
|
.h(height)
|
||||||
.into_any_element(),
|
.child(no_changes_state)
|
||||||
),
|
.into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"Unknown Upstream",
|
single_example(
|
||||||
div()
|
"Unknown Upstream",
|
||||||
.w(width)
|
div()
|
||||||
.h(height)
|
.w(width)
|
||||||
.child(unknown_upstream_state)
|
.h(height)
|
||||||
.into_any_element(),
|
.child(unknown_upstream_state)
|
||||||
),
|
.into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"Ahead of Remote",
|
single_example(
|
||||||
div()
|
"Ahead of Remote",
|
||||||
.w(width)
|
div()
|
||||||
.h(height)
|
.w(width)
|
||||||
.child(ahead_of_upstream_state)
|
.h(height)
|
||||||
.into_any_element(),
|
.child(ahead_of_upstream_state)
|
||||||
),
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.vertical(),
|
||||||
])
|
])
|
||||||
.vertical(),
|
.into_any_element(),
|
||||||
])
|
)
|
||||||
.into_any_element()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,8 +33,7 @@ impl From<IconName> for ToastIcon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(IntoComponent)]
|
#[derive(RegisterComponent)]
|
||||||
#[component(scope = "Notification")]
|
|
||||||
pub struct StatusToast {
|
pub struct StatusToast {
|
||||||
icon: Option<ToastIcon>,
|
icon: Option<ToastIcon>,
|
||||||
text: SharedString,
|
text: SharedString,
|
||||||
|
@ -135,8 +134,12 @@ impl Focusable for StatusToast {
|
||||||
|
|
||||||
impl EventEmitter<DismissEvent> for StatusToast {}
|
impl EventEmitter<DismissEvent> for StatusToast {}
|
||||||
|
|
||||||
impl ComponentPreview for StatusToast {
|
impl Component for StatusToast {
|
||||||
fn preview(_window: &mut Window, cx: &mut App) -> AnyElement {
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::Notification
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, cx: &mut App) -> Option<AnyElement> {
|
||||||
let text_example = StatusToast::new("Operation completed", cx, |this, _| this);
|
let text_example = StatusToast::new("Operation completed", cx, |this, _| this);
|
||||||
|
|
||||||
let action_example = StatusToast::new("Update ready to install", cx, |this, _cx| {
|
let action_example = StatusToast::new("Update ready to install", cx, |this, _cx| {
|
||||||
|
@ -175,29 +178,40 @@ impl ComponentPreview for StatusToast {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
v_flex()
|
Some(
|
||||||
.gap_6()
|
v_flex()
|
||||||
.p_4()
|
.gap_6()
|
||||||
.children(vec![
|
.p_4()
|
||||||
example_group_with_title(
|
.children(vec![
|
||||||
"Basic Toast",
|
example_group_with_title(
|
||||||
vec![
|
"Basic Toast",
|
||||||
single_example("Text", div().child(text_example).into_any_element()),
|
vec![
|
||||||
single_example("Action", div().child(action_example).into_any_element()),
|
single_example("Text", div().child(text_example).into_any_element()),
|
||||||
single_example("Icon", div().child(icon_example).into_any_element()),
|
single_example(
|
||||||
],
|
"Action",
|
||||||
),
|
div().child(action_example).into_any_element(),
|
||||||
example_group_with_title(
|
),
|
||||||
"Examples",
|
single_example("Icon", div().child(icon_example).into_any_element()),
|
||||||
vec![
|
],
|
||||||
single_example("Success", div().child(success_example).into_any_element()),
|
),
|
||||||
single_example("Error", div().child(error_example).into_any_element()),
|
example_group_with_title(
|
||||||
single_example("Warning", div().child(warning_example).into_any_element()),
|
"Examples",
|
||||||
single_example("Create PR", div().child(pr_example).into_any_element()),
|
vec![
|
||||||
],
|
single_example(
|
||||||
)
|
"Success",
|
||||||
.vertical(),
|
div().child(success_example).into_any_element(),
|
||||||
])
|
),
|
||||||
.into_any_element()
|
single_example("Error", div().child(error_example).into_any_element()),
|
||||||
|
single_example(
|
||||||
|
"Warning",
|
||||||
|
div().child(warning_example).into_any_element(),
|
||||||
|
),
|
||||||
|
single_example("Create PR", div().child(pr_example).into_any_element()),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.vertical(),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,7 @@ pub enum ComponentStory {
|
||||||
ContextMenu,
|
ContextMenu,
|
||||||
Cursor,
|
Cursor,
|
||||||
DefaultColors,
|
DefaultColors,
|
||||||
Disclosure,
|
|
||||||
Focus,
|
Focus,
|
||||||
Icon,
|
|
||||||
IconButton,
|
IconButton,
|
||||||
Keybinding,
|
Keybinding,
|
||||||
List,
|
List,
|
||||||
|
@ -35,7 +33,6 @@ pub enum ComponentStory {
|
||||||
ToggleButton,
|
ToggleButton,
|
||||||
ViewportUnits,
|
ViewportUnits,
|
||||||
WithRemSize,
|
WithRemSize,
|
||||||
Vector,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentStory {
|
impl ComponentStory {
|
||||||
|
@ -51,9 +48,7 @@ impl ComponentStory {
|
||||||
Self::ContextMenu => cx.new(|_| ui::ContextMenuStory).into(),
|
Self::ContextMenu => cx.new(|_| ui::ContextMenuStory).into(),
|
||||||
Self::Cursor => cx.new(|_| crate::stories::CursorStory).into(),
|
Self::Cursor => cx.new(|_| crate::stories::CursorStory).into(),
|
||||||
Self::DefaultColors => DefaultColorsStory::model(cx).into(),
|
Self::DefaultColors => DefaultColorsStory::model(cx).into(),
|
||||||
Self::Disclosure => cx.new(|_| ui::DisclosureStory).into(),
|
|
||||||
Self::Focus => FocusStory::model(window, cx).into(),
|
Self::Focus => FocusStory::model(window, cx).into(),
|
||||||
Self::Icon => cx.new(|_| ui::IconStory).into(),
|
|
||||||
Self::IconButton => cx.new(|_| ui::IconButtonStory).into(),
|
Self::IconButton => cx.new(|_| ui::IconButtonStory).into(),
|
||||||
Self::Keybinding => cx.new(|_| ui::KeybindingStory).into(),
|
Self::Keybinding => cx.new(|_| ui::KeybindingStory).into(),
|
||||||
Self::List => cx.new(|_| ui::ListStory).into(),
|
Self::List => cx.new(|_| ui::ListStory).into(),
|
||||||
|
@ -68,7 +63,6 @@ impl ComponentStory {
|
||||||
Self::ToggleButton => cx.new(|_| ui::ToggleButtonStory).into(),
|
Self::ToggleButton => cx.new(|_| ui::ToggleButtonStory).into(),
|
||||||
Self::ViewportUnits => cx.new(|_| crate::stories::ViewportUnitsStory).into(),
|
Self::ViewportUnits => cx.new(|_| crate::stories::ViewportUnitsStory).into(),
|
||||||
Self::WithRemSize => cx.new(|_| crate::stories::WithRemSizeStory).into(),
|
Self::WithRemSize => cx.new(|_| crate::stories::WithRemSizeStory).into(),
|
||||||
Self::Vector => cx.new(|_| ui::VectorStory).into(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ strum.workspace = true
|
||||||
theme.workspace = true
|
theme.workspace = true
|
||||||
ui_macros.workspace = true
|
ui_macros.workspace = true
|
||||||
util.workspace = true
|
util.workspace = true
|
||||||
|
documented = "0.9.1"
|
||||||
workspace-hack.workspace = true
|
workspace-hack.workspace = true
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
|
|
5
crates/ui/src/component_prelude.rs
Normal file
5
crates/ui/src/component_prelude.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
pub use component::{
|
||||||
|
Component, ComponentScope, example_group, example_group_with_title, single_example,
|
||||||
|
};
|
||||||
|
pub use documented::Documented;
|
||||||
|
pub use ui_macros::RegisterComponent;
|
|
@ -73,7 +73,5 @@ pub use table::*;
|
||||||
pub use toggle::*;
|
pub use toggle::*;
|
||||||
pub use tooltip::*;
|
pub use tooltip::*;
|
||||||
|
|
||||||
#[cfg(feature = "stories")]
|
|
||||||
pub use image::story::*;
|
|
||||||
#[cfg(feature = "stories")]
|
#[cfg(feature = "stories")]
|
||||||
pub use stories::*;
|
pub use stories::*;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
use documented::Documented;
|
||||||
use gpui::{AnyElement, Hsla, ImageSource, Img, IntoElement, Styled, img};
|
use gpui::{AnyElement, Hsla, ImageSource, Img, IntoElement, Styled, img};
|
||||||
|
|
||||||
/// An element that renders a user avatar with customizable appearance options.
|
/// An element that renders a user avatar with customizable appearance options.
|
||||||
|
@ -14,7 +15,7 @@ use gpui::{AnyElement, Hsla, ImageSource, Img, IntoElement, Styled, img};
|
||||||
/// .grayscale(true)
|
/// .grayscale(true)
|
||||||
/// .border_color(gpui::red());
|
/// .border_color(gpui::red());
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(IntoElement, IntoComponent)]
|
#[derive(IntoElement, Documented, RegisterComponent)]
|
||||||
pub struct Avatar {
|
pub struct Avatar {
|
||||||
image: Img,
|
image: Img,
|
||||||
size: Option<AbsoluteLength>,
|
size: Option<AbsoluteLength>,
|
||||||
|
@ -219,84 +220,102 @@ impl RenderOnce for AvatarAvailabilityIndicator {
|
||||||
}
|
}
|
||||||
|
|
||||||
// View this component preview using `workspace: open component-preview`
|
// View this component preview using `workspace: open component-preview`
|
||||||
impl ComponentPreview for Avatar {
|
impl Component for Avatar {
|
||||||
fn preview(_window: &mut Window, cx: &mut App) -> AnyElement {
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::Collaboration
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some(Avatar::DOCS)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, cx: &mut App) -> Option<AnyElement> {
|
||||||
let example_avatar = "https://avatars.githubusercontent.com/u/1714999?v=4";
|
let example_avatar = "https://avatars.githubusercontent.com/u/1714999?v=4";
|
||||||
|
|
||||||
v_flex()
|
Some(
|
||||||
.gap_6()
|
v_flex()
|
||||||
.children(vec![
|
.gap_6()
|
||||||
example_group_with_title(
|
.children(vec![
|
||||||
"Sizes",
|
example_group_with_title(
|
||||||
vec![
|
"Sizes",
|
||||||
single_example("Default", Avatar::new(example_avatar).into_any_element()),
|
vec![
|
||||||
single_example(
|
single_example(
|
||||||
"Small",
|
"Default",
|
||||||
Avatar::new(example_avatar).size(px(24.)).into_any_element(),
|
Avatar::new(example_avatar).into_any_element(),
|
||||||
),
|
),
|
||||||
single_example(
|
single_example(
|
||||||
"Large",
|
"Small",
|
||||||
Avatar::new(example_avatar).size(px(48.)).into_any_element(),
|
Avatar::new(example_avatar).size(px(24.)).into_any_element(),
|
||||||
),
|
),
|
||||||
],
|
single_example(
|
||||||
),
|
"Large",
|
||||||
example_group_with_title(
|
Avatar::new(example_avatar).size(px(48.)).into_any_element(),
|
||||||
"Styles",
|
),
|
||||||
vec![
|
],
|
||||||
single_example("Default", Avatar::new(example_avatar).into_any_element()),
|
),
|
||||||
single_example(
|
example_group_with_title(
|
||||||
"Grayscale",
|
"Styles",
|
||||||
Avatar::new(example_avatar)
|
vec![
|
||||||
.grayscale(true)
|
single_example(
|
||||||
.into_any_element(),
|
"Default",
|
||||||
),
|
Avatar::new(example_avatar).into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"With Border",
|
single_example(
|
||||||
Avatar::new(example_avatar)
|
"Grayscale",
|
||||||
.border_color(cx.theme().colors().border)
|
Avatar::new(example_avatar)
|
||||||
.into_any_element(),
|
.grayscale(true)
|
||||||
),
|
.into_any_element(),
|
||||||
],
|
),
|
||||||
),
|
single_example(
|
||||||
example_group_with_title(
|
"With Border",
|
||||||
"Audio Status",
|
Avatar::new(example_avatar)
|
||||||
vec![
|
.border_color(cx.theme().colors().border)
|
||||||
single_example(
|
.into_any_element(),
|
||||||
"Muted",
|
),
|
||||||
Avatar::new(example_avatar)
|
],
|
||||||
.indicator(AvatarAudioStatusIndicator::new(AudioStatus::Muted))
|
),
|
||||||
.into_any_element(),
|
example_group_with_title(
|
||||||
),
|
"Audio Status",
|
||||||
single_example(
|
vec![
|
||||||
"Deafened",
|
single_example(
|
||||||
Avatar::new(example_avatar)
|
"Muted",
|
||||||
.indicator(AvatarAudioStatusIndicator::new(AudioStatus::Deafened))
|
Avatar::new(example_avatar)
|
||||||
.into_any_element(),
|
.indicator(AvatarAudioStatusIndicator::new(AudioStatus::Muted))
|
||||||
),
|
.into_any_element(),
|
||||||
],
|
),
|
||||||
),
|
single_example(
|
||||||
example_group_with_title(
|
"Deafened",
|
||||||
"Availability",
|
Avatar::new(example_avatar)
|
||||||
vec![
|
.indicator(AvatarAudioStatusIndicator::new(
|
||||||
single_example(
|
AudioStatus::Deafened,
|
||||||
"Free",
|
))
|
||||||
Avatar::new(example_avatar)
|
.into_any_element(),
|
||||||
.indicator(AvatarAvailabilityIndicator::new(
|
),
|
||||||
CollaboratorAvailability::Free,
|
],
|
||||||
))
|
),
|
||||||
.into_any_element(),
|
example_group_with_title(
|
||||||
),
|
"Availability",
|
||||||
single_example(
|
vec![
|
||||||
"Busy",
|
single_example(
|
||||||
Avatar::new(example_avatar)
|
"Free",
|
||||||
.indicator(AvatarAvailabilityIndicator::new(
|
Avatar::new(example_avatar)
|
||||||
CollaboratorAvailability::Busy,
|
.indicator(AvatarAvailabilityIndicator::new(
|
||||||
))
|
CollaboratorAvailability::Free,
|
||||||
.into_any_element(),
|
))
|
||||||
),
|
.into_any_element(),
|
||||||
],
|
),
|
||||||
),
|
single_example(
|
||||||
])
|
"Busy",
|
||||||
.into_any_element()
|
Avatar::new(example_avatar)
|
||||||
|
.indicator(AvatarAvailabilityIndicator::new(
|
||||||
|
CollaboratorAvailability::Busy,
|
||||||
|
))
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,7 @@ pub enum Severity {
|
||||||
/// .icon_position(IconPosition::End),
|
/// .icon_position(IconPosition::End),
|
||||||
/// )
|
/// )
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(IntoElement, IntoComponent)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
#[component(scope = "Notification")]
|
|
||||||
pub struct Banner {
|
pub struct Banner {
|
||||||
severity: Severity,
|
severity: Severity,
|
||||||
children: Option<AnyElement>,
|
children: Option<AnyElement>,
|
||||||
|
@ -137,8 +136,12 @@ impl RenderOnce for Banner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentPreview for Banner {
|
impl Component for Banner {
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::Notification
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
let severity_examples = vec![
|
let severity_examples = vec![
|
||||||
single_example(
|
single_example(
|
||||||
"Default",
|
"Default",
|
||||||
|
@ -185,8 +188,10 @@ impl ComponentPreview for Banner {
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
example_group(severity_examples)
|
Some(
|
||||||
.vertical()
|
example_group(severity_examples)
|
||||||
.into_any_element()
|
.vertical()
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use component::{ComponentPreview, example_group_with_title, single_example};
|
use crate::component_prelude::*;
|
||||||
use gpui::{AnyElement, AnyView, DefiniteLength};
|
use gpui::{AnyElement, AnyView, DefiniteLength};
|
||||||
use ui_macros::IntoComponent;
|
use ui_macros::RegisterComponent;
|
||||||
|
|
||||||
use crate::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, IconName, IconSize, Label};
|
use crate::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, IconName, IconSize, Label};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -77,8 +77,7 @@ use super::button_icon::ButtonIcon;
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
#[derive(IntoElement, IntoComponent)]
|
#[derive(IntoElement, Documented, RegisterComponent)]
|
||||||
#[component(scope = "Input")]
|
|
||||||
pub struct Button {
|
pub struct Button {
|
||||||
base: ButtonLike,
|
base: ButtonLike,
|
||||||
label: SharedString,
|
label: SharedString,
|
||||||
|
@ -466,121 +465,135 @@ impl RenderOnce for Button {
|
||||||
}
|
}
|
||||||
|
|
||||||
// View this component preview using `workspace: open component-preview`
|
// View this component preview using `workspace: open component-preview`
|
||||||
impl ComponentPreview for Button {
|
impl Component for Button {
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
fn scope() -> ComponentScope {
|
||||||
v_flex()
|
ComponentScope::Input
|
||||||
.gap_6()
|
}
|
||||||
.children(vec![
|
|
||||||
example_group_with_title(
|
fn sort_name() -> &'static str {
|
||||||
"Button Styles",
|
"ButtonA"
|
||||||
vec![
|
}
|
||||||
single_example(
|
|
||||||
"Default",
|
fn description() -> Option<&'static str> {
|
||||||
Button::new("default", "Default").into_any_element(),
|
Some("A button triggers an event or action.")
|
||||||
),
|
}
|
||||||
single_example(
|
|
||||||
"Filled",
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
Button::new("filled", "Filled")
|
Some(
|
||||||
.style(ButtonStyle::Filled)
|
v_flex()
|
||||||
.into_any_element(),
|
.gap_6()
|
||||||
),
|
.children(vec![
|
||||||
single_example(
|
example_group_with_title(
|
||||||
"Subtle",
|
"Button Styles",
|
||||||
Button::new("outline", "Subtle")
|
vec![
|
||||||
.style(ButtonStyle::Subtle)
|
single_example(
|
||||||
.into_any_element(),
|
"Default",
|
||||||
),
|
Button::new("default", "Default").into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"Tinted",
|
single_example(
|
||||||
Button::new("tinted_accent_style", "Accent")
|
"Filled",
|
||||||
.style(ButtonStyle::Tinted(TintColor::Accent))
|
Button::new("filled", "Filled")
|
||||||
.into_any_element(),
|
.style(ButtonStyle::Filled)
|
||||||
),
|
.into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"Transparent",
|
single_example(
|
||||||
Button::new("transparent", "Transparent")
|
"Subtle",
|
||||||
.style(ButtonStyle::Transparent)
|
Button::new("outline", "Subtle")
|
||||||
.into_any_element(),
|
.style(ButtonStyle::Subtle)
|
||||||
),
|
.into_any_element(),
|
||||||
],
|
),
|
||||||
),
|
single_example(
|
||||||
example_group_with_title(
|
"Tinted",
|
||||||
"Tint Styles",
|
Button::new("tinted_accent_style", "Accent")
|
||||||
vec![
|
.style(ButtonStyle::Tinted(TintColor::Accent))
|
||||||
single_example(
|
.into_any_element(),
|
||||||
"Accent",
|
),
|
||||||
Button::new("tinted_accent", "Accent")
|
single_example(
|
||||||
.style(ButtonStyle::Tinted(TintColor::Accent))
|
"Transparent",
|
||||||
.into_any_element(),
|
Button::new("transparent", "Transparent")
|
||||||
),
|
.style(ButtonStyle::Transparent)
|
||||||
single_example(
|
.into_any_element(),
|
||||||
"Error",
|
),
|
||||||
Button::new("tinted_negative", "Error")
|
],
|
||||||
.style(ButtonStyle::Tinted(TintColor::Error))
|
),
|
||||||
.into_any_element(),
|
example_group_with_title(
|
||||||
),
|
"Tint Styles",
|
||||||
single_example(
|
vec![
|
||||||
"Warning",
|
single_example(
|
||||||
Button::new("tinted_warning", "Warning")
|
"Accent",
|
||||||
.style(ButtonStyle::Tinted(TintColor::Warning))
|
Button::new("tinted_accent", "Accent")
|
||||||
.into_any_element(),
|
.style(ButtonStyle::Tinted(TintColor::Accent))
|
||||||
),
|
.into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"Success",
|
single_example(
|
||||||
Button::new("tinted_positive", "Success")
|
"Error",
|
||||||
.style(ButtonStyle::Tinted(TintColor::Success))
|
Button::new("tinted_negative", "Error")
|
||||||
.into_any_element(),
|
.style(ButtonStyle::Tinted(TintColor::Error))
|
||||||
),
|
.into_any_element(),
|
||||||
],
|
),
|
||||||
),
|
single_example(
|
||||||
example_group_with_title(
|
"Warning",
|
||||||
"Special States",
|
Button::new("tinted_warning", "Warning")
|
||||||
vec![
|
.style(ButtonStyle::Tinted(TintColor::Warning))
|
||||||
single_example(
|
.into_any_element(),
|
||||||
"Default",
|
),
|
||||||
Button::new("default_state", "Default").into_any_element(),
|
single_example(
|
||||||
),
|
"Success",
|
||||||
single_example(
|
Button::new("tinted_positive", "Success")
|
||||||
"Disabled",
|
.style(ButtonStyle::Tinted(TintColor::Success))
|
||||||
Button::new("disabled", "Disabled")
|
.into_any_element(),
|
||||||
.disabled(true)
|
),
|
||||||
.into_any_element(),
|
],
|
||||||
),
|
),
|
||||||
single_example(
|
example_group_with_title(
|
||||||
"Selected",
|
"Special States",
|
||||||
Button::new("selected", "Selected")
|
vec![
|
||||||
.toggle_state(true)
|
single_example(
|
||||||
.into_any_element(),
|
"Default",
|
||||||
),
|
Button::new("default_state", "Default").into_any_element(),
|
||||||
],
|
),
|
||||||
),
|
single_example(
|
||||||
example_group_with_title(
|
"Disabled",
|
||||||
"Buttons with Icons",
|
Button::new("disabled", "Disabled")
|
||||||
vec![
|
.disabled(true)
|
||||||
single_example(
|
.into_any_element(),
|
||||||
"Icon Start",
|
),
|
||||||
Button::new("icon_start", "Icon Start")
|
single_example(
|
||||||
.icon(IconName::Check)
|
"Selected",
|
||||||
.icon_position(IconPosition::Start)
|
Button::new("selected", "Selected")
|
||||||
.into_any_element(),
|
.toggle_state(true)
|
||||||
),
|
.into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"Icon End",
|
],
|
||||||
Button::new("icon_end", "Icon End")
|
),
|
||||||
.icon(IconName::Check)
|
example_group_with_title(
|
||||||
.icon_position(IconPosition::End)
|
"Buttons with Icons",
|
||||||
.into_any_element(),
|
vec![
|
||||||
),
|
single_example(
|
||||||
single_example(
|
"Icon Start",
|
||||||
"Icon Color",
|
Button::new("icon_start", "Icon Start")
|
||||||
Button::new("icon_color", "Icon Color")
|
.icon(IconName::Check)
|
||||||
.icon(IconName::Check)
|
.icon_position(IconPosition::Start)
|
||||||
.icon_color(Color::Accent)
|
.into_any_element(),
|
||||||
.into_any_element(),
|
),
|
||||||
),
|
single_example(
|
||||||
],
|
"Icon End",
|
||||||
),
|
Button::new("icon_end", "Icon End")
|
||||||
])
|
.icon(IconName::Check)
|
||||||
.into_any_element()
|
.icon_position(IconPosition::End)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Icon Color",
|
||||||
|
Button::new("icon_color", "Icon Color")
|
||||||
|
.icon(IconName::Check)
|
||||||
|
.icon_color(Color::Accent)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use gpui::Hsla;
|
||||||
///
|
///
|
||||||
/// Can be used as either an icon alongside a label, like in [`Button`](crate::Button),
|
/// Can be used as either an icon alongside a label, like in [`Button`](crate::Button),
|
||||||
/// or as a standalone icon, like in [`IconButton`](crate::IconButton).
|
/// or as a standalone icon, like in [`IconButton`](crate::IconButton).
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub(super) struct ButtonIcon {
|
pub(super) struct ButtonIcon {
|
||||||
icon: IconName,
|
icon: IconName,
|
||||||
size: IconSize,
|
size: IconSize,
|
||||||
|
@ -39,7 +39,6 @@ impl ButtonIcon {
|
||||||
if let Some(size) = size.into() {
|
if let Some(size) = size.into() {
|
||||||
self.size = size;
|
self.size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +46,6 @@ impl ButtonIcon {
|
||||||
if let Some(color) = color.into() {
|
if let Some(color) = color.into() {
|
||||||
self.color = color;
|
self.color = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,3 +118,82 @@ impl RenderOnce for ButtonIcon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Component for ButtonIcon {
|
||||||
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::Input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"ButtonIcon"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some("An icon component specifically designed for use within buttons.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
|
Some(
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.children(vec![
|
||||||
|
example_group_with_title(
|
||||||
|
"Basic Usage",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Default",
|
||||||
|
ButtonIcon::new(IconName::Star).into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Custom Size",
|
||||||
|
ButtonIcon::new(IconName::Star)
|
||||||
|
.size(IconSize::Medium)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Custom Color",
|
||||||
|
ButtonIcon::new(IconName::Star)
|
||||||
|
.color(Color::Accent)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"States",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Selected",
|
||||||
|
ButtonIcon::new(IconName::Star)
|
||||||
|
.toggle_state(true)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Disabled",
|
||||||
|
ButtonIcon::new(IconName::Star)
|
||||||
|
.disabled(true)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"With Indicator",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Default Indicator",
|
||||||
|
ButtonIcon::new(IconName::Star)
|
||||||
|
.indicator(Indicator::dot())
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Custom Indicator",
|
||||||
|
ButtonIcon::new(IconName::Star)
|
||||||
|
.indicator(Indicator::dot().color(Color::Error))
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
use gpui::{AnyElement, AnyView, ClickEvent, Hsla, Rems, transparent_black};
|
use documented::Documented;
|
||||||
use gpui::{CursorStyle, DefiniteLength, MouseButton, MouseDownEvent, MouseUpEvent, relative};
|
use gpui::{
|
||||||
|
AnyElement, AnyView, ClickEvent, CursorStyle, DefiniteLength, Hsla, MouseButton,
|
||||||
|
MouseDownEvent, MouseUpEvent, Rems, relative, transparent_black,
|
||||||
|
};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{DynamicSpacing, ElevationIndex, prelude::*};
|
use crate::{DynamicSpacing, ElevationIndex, prelude::*};
|
||||||
|
@ -343,7 +346,7 @@ impl ButtonSize {
|
||||||
/// unconstrained and may make the UI feel less consistent.
|
/// unconstrained and may make the UI feel less consistent.
|
||||||
///
|
///
|
||||||
/// This is also used to build the prebuilt buttons.
|
/// This is also used to build the prebuilt buttons.
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement, Documented, RegisterComponent)]
|
||||||
pub struct ButtonLike {
|
pub struct ButtonLike {
|
||||||
pub(super) base: Div,
|
pub(super) base: Div,
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
|
@ -585,3 +588,99 @@ impl RenderOnce for ButtonLike {
|
||||||
.children(self.children)
|
.children(self.children)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Component for ButtonLike {
|
||||||
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::Input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sort_name() -> &'static str {
|
||||||
|
// ButtonLike should be at the bottom of the button list
|
||||||
|
"ButtonZ"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some(ButtonLike::DOCS)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
|
Some(
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.children(vec![
|
||||||
|
example_group(vec![
|
||||||
|
single_example(
|
||||||
|
"Default",
|
||||||
|
ButtonLike::new("default")
|
||||||
|
.child(Label::new("Default"))
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Filled",
|
||||||
|
ButtonLike::new("filled")
|
||||||
|
.style(ButtonStyle::Filled)
|
||||||
|
.child(Label::new("Filled"))
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Subtle",
|
||||||
|
ButtonLike::new("outline")
|
||||||
|
.style(ButtonStyle::Subtle)
|
||||||
|
.child(Label::new("Subtle"))
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Tinted",
|
||||||
|
ButtonLike::new("tinted_accent_style")
|
||||||
|
.style(ButtonStyle::Tinted(TintColor::Accent))
|
||||||
|
.child(Label::new("Accent"))
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Transparent",
|
||||||
|
ButtonLike::new("transparent")
|
||||||
|
.style(ButtonStyle::Transparent)
|
||||||
|
.child(Label::new("Transparent"))
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
example_group_with_title(
|
||||||
|
"Button Group Constructors",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Left Rounded",
|
||||||
|
ButtonLike::new_rounded_left("left_rounded")
|
||||||
|
.child(Label::new("Left Rounded"))
|
||||||
|
.style(ButtonStyle::Filled)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Right Rounded",
|
||||||
|
ButtonLike::new_rounded_right("right_rounded")
|
||||||
|
.child(Label::new("Right Rounded"))
|
||||||
|
.style(ButtonStyle::Filled)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Button Group",
|
||||||
|
h_flex()
|
||||||
|
.gap_px()
|
||||||
|
.child(
|
||||||
|
ButtonLike::new_rounded_left("bg_left")
|
||||||
|
.child(Label::new("Left"))
|
||||||
|
.style(ButtonStyle::Filled),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
ButtonLike::new_rounded_right("bg_right")
|
||||||
|
.child(Label::new("Right"))
|
||||||
|
.style(ButtonStyle::Filled),
|
||||||
|
)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -13,8 +13,7 @@ pub enum IconButtonShape {
|
||||||
Wide,
|
Wide,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(IntoElement, IntoComponent)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
#[component(scope = "Input")]
|
|
||||||
pub struct IconButton {
|
pub struct IconButton {
|
||||||
base: ButtonLike,
|
base: ButtonLike,
|
||||||
shape: IconButtonShape,
|
shape: IconButtonShape,
|
||||||
|
@ -210,159 +209,169 @@ impl RenderOnce for IconButton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentPreview for IconButton {
|
impl Component for IconButton {
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
fn scope() -> ComponentScope {
|
||||||
v_flex()
|
ComponentScope::Input
|
||||||
.gap_6()
|
}
|
||||||
.children(vec![
|
|
||||||
example_group_with_title(
|
fn sort_name() -> &'static str {
|
||||||
"Icon Button Styles",
|
"ButtonB"
|
||||||
vec![
|
}
|
||||||
single_example(
|
|
||||||
"Default",
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
IconButton::new("default", IconName::Check)
|
Some(
|
||||||
.layer(ElevationIndex::Background)
|
v_flex()
|
||||||
.into_any_element(),
|
.gap_6()
|
||||||
),
|
.children(vec![
|
||||||
single_example(
|
example_group_with_title(
|
||||||
"Filled",
|
"Icon Button Styles",
|
||||||
IconButton::new("filled", IconName::Check)
|
vec![
|
||||||
.layer(ElevationIndex::Background)
|
single_example(
|
||||||
.style(ButtonStyle::Filled)
|
"Default",
|
||||||
.into_any_element(),
|
IconButton::new("default", IconName::Check)
|
||||||
),
|
.layer(ElevationIndex::Background)
|
||||||
single_example(
|
.into_any_element(),
|
||||||
"Subtle",
|
),
|
||||||
IconButton::new("subtle", IconName::Check)
|
single_example(
|
||||||
.layer(ElevationIndex::Background)
|
"Filled",
|
||||||
.style(ButtonStyle::Subtle)
|
IconButton::new("filled", IconName::Check)
|
||||||
.into_any_element(),
|
.layer(ElevationIndex::Background)
|
||||||
),
|
.style(ButtonStyle::Filled)
|
||||||
single_example(
|
.into_any_element(),
|
||||||
"Tinted",
|
),
|
||||||
IconButton::new("tinted", IconName::Check)
|
single_example(
|
||||||
.layer(ElevationIndex::Background)
|
"Subtle",
|
||||||
.style(ButtonStyle::Tinted(TintColor::Accent))
|
IconButton::new("subtle", IconName::Check)
|
||||||
.into_any_element(),
|
.layer(ElevationIndex::Background)
|
||||||
),
|
.style(ButtonStyle::Subtle)
|
||||||
single_example(
|
.into_any_element(),
|
||||||
"Transparent",
|
),
|
||||||
IconButton::new("transparent", IconName::Check)
|
single_example(
|
||||||
.layer(ElevationIndex::Background)
|
"Tinted",
|
||||||
.style(ButtonStyle::Transparent)
|
IconButton::new("tinted", IconName::Check)
|
||||||
.into_any_element(),
|
.layer(ElevationIndex::Background)
|
||||||
),
|
.style(ButtonStyle::Tinted(TintColor::Accent))
|
||||||
],
|
.into_any_element(),
|
||||||
),
|
),
|
||||||
example_group_with_title(
|
single_example(
|
||||||
"Icon Button Shapes",
|
"Transparent",
|
||||||
vec![
|
IconButton::new("transparent", IconName::Check)
|
||||||
single_example(
|
.layer(ElevationIndex::Background)
|
||||||
"Square",
|
.style(ButtonStyle::Transparent)
|
||||||
IconButton::new("square", IconName::Check)
|
.into_any_element(),
|
||||||
.shape(IconButtonShape::Square)
|
),
|
||||||
.style(ButtonStyle::Filled)
|
],
|
||||||
.layer(ElevationIndex::Background)
|
),
|
||||||
.into_any_element(),
|
example_group_with_title(
|
||||||
),
|
"Icon Button Shapes",
|
||||||
single_example(
|
vec![
|
||||||
"Wide",
|
single_example(
|
||||||
IconButton::new("wide", IconName::Check)
|
"Square",
|
||||||
.shape(IconButtonShape::Wide)
|
IconButton::new("square", IconName::Check)
|
||||||
.style(ButtonStyle::Filled)
|
.shape(IconButtonShape::Square)
|
||||||
.layer(ElevationIndex::Background)
|
.style(ButtonStyle::Filled)
|
||||||
.into_any_element(),
|
.layer(ElevationIndex::Background)
|
||||||
),
|
.into_any_element(),
|
||||||
],
|
),
|
||||||
),
|
single_example(
|
||||||
example_group_with_title(
|
"Wide",
|
||||||
"Icon Button Sizes",
|
IconButton::new("wide", IconName::Check)
|
||||||
vec![
|
.shape(IconButtonShape::Wide)
|
||||||
single_example(
|
.style(ButtonStyle::Filled)
|
||||||
"Small",
|
.layer(ElevationIndex::Background)
|
||||||
IconButton::new("small", IconName::Check)
|
.into_any_element(),
|
||||||
.icon_size(IconSize::XSmall)
|
),
|
||||||
.style(ButtonStyle::Filled)
|
],
|
||||||
.layer(ElevationIndex::Background)
|
),
|
||||||
.into_any_element(),
|
example_group_with_title(
|
||||||
),
|
"Icon Button Sizes",
|
||||||
single_example(
|
vec![
|
||||||
"Small",
|
single_example(
|
||||||
IconButton::new("small", IconName::Check)
|
"XSmall",
|
||||||
.icon_size(IconSize::Small)
|
IconButton::new("xsmall", IconName::Check)
|
||||||
.style(ButtonStyle::Filled)
|
.icon_size(IconSize::XSmall)
|
||||||
.layer(ElevationIndex::Background)
|
.style(ButtonStyle::Filled)
|
||||||
.into_any_element(),
|
.layer(ElevationIndex::Background)
|
||||||
),
|
.into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"Medium",
|
single_example(
|
||||||
IconButton::new("medium", IconName::Check)
|
"Small",
|
||||||
.icon_size(IconSize::Medium)
|
IconButton::new("small", IconName::Check)
|
||||||
.style(ButtonStyle::Filled)
|
.icon_size(IconSize::Small)
|
||||||
.layer(ElevationIndex::Background)
|
.style(ButtonStyle::Filled)
|
||||||
.into_any_element(),
|
.layer(ElevationIndex::Background)
|
||||||
),
|
.into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"XLarge",
|
single_example(
|
||||||
IconButton::new("xlarge", IconName::Check)
|
"Medium",
|
||||||
.icon_size(IconSize::XLarge)
|
IconButton::new("medium", IconName::Check)
|
||||||
.style(ButtonStyle::Filled)
|
.icon_size(IconSize::Medium)
|
||||||
.layer(ElevationIndex::Background)
|
.style(ButtonStyle::Filled)
|
||||||
.into_any_element(),
|
.layer(ElevationIndex::Background)
|
||||||
),
|
.into_any_element(),
|
||||||
],
|
),
|
||||||
),
|
single_example(
|
||||||
example_group_with_title(
|
"XLarge",
|
||||||
"Special States",
|
IconButton::new("xlarge", IconName::Check)
|
||||||
vec![
|
.icon_size(IconSize::XLarge)
|
||||||
single_example(
|
.style(ButtonStyle::Filled)
|
||||||
"Disabled",
|
.layer(ElevationIndex::Background)
|
||||||
IconButton::new("disabled", IconName::Check)
|
.into_any_element(),
|
||||||
.disabled(true)
|
),
|
||||||
.style(ButtonStyle::Filled)
|
],
|
||||||
.layer(ElevationIndex::Background)
|
),
|
||||||
.into_any_element(),
|
example_group_with_title(
|
||||||
),
|
"Special States",
|
||||||
single_example(
|
vec![
|
||||||
"Selected",
|
single_example(
|
||||||
IconButton::new("selected", IconName::Check)
|
"Disabled",
|
||||||
.toggle_state(true)
|
IconButton::new("disabled", IconName::Check)
|
||||||
.style(ButtonStyle::Filled)
|
.disabled(true)
|
||||||
.layer(ElevationIndex::Background)
|
.style(ButtonStyle::Filled)
|
||||||
.into_any_element(),
|
.layer(ElevationIndex::Background)
|
||||||
),
|
.into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"With Indicator",
|
single_example(
|
||||||
IconButton::new("indicator", IconName::Check)
|
"Selected",
|
||||||
.indicator(Indicator::dot().color(Color::Success))
|
IconButton::new("selected", IconName::Check)
|
||||||
.style(ButtonStyle::Filled)
|
.toggle_state(true)
|
||||||
.layer(ElevationIndex::Background)
|
.style(ButtonStyle::Filled)
|
||||||
.into_any_element(),
|
.layer(ElevationIndex::Background)
|
||||||
),
|
.into_any_element(),
|
||||||
],
|
),
|
||||||
),
|
single_example(
|
||||||
example_group_with_title(
|
"With Indicator",
|
||||||
"Custom Colors",
|
IconButton::new("indicator", IconName::Check)
|
||||||
vec![
|
.indicator(Indicator::dot().color(Color::Success))
|
||||||
single_example(
|
.style(ButtonStyle::Filled)
|
||||||
"Custom Icon Color",
|
.layer(ElevationIndex::Background)
|
||||||
IconButton::new("custom_color", IconName::Check)
|
.into_any_element(),
|
||||||
.icon_color(Color::Accent)
|
),
|
||||||
.style(ButtonStyle::Filled)
|
],
|
||||||
.layer(ElevationIndex::Background)
|
),
|
||||||
.into_any_element(),
|
example_group_with_title(
|
||||||
),
|
"Custom Colors",
|
||||||
single_example(
|
vec![
|
||||||
"With Alpha",
|
single_example(
|
||||||
IconButton::new("alpha", IconName::Check)
|
"Custom Icon Color",
|
||||||
.alpha(0.5)
|
IconButton::new("custom_color", IconName::Check)
|
||||||
.style(ButtonStyle::Filled)
|
.icon_color(Color::Accent)
|
||||||
.layer(ElevationIndex::Background)
|
.style(ButtonStyle::Filled)
|
||||||
.into_any_element(),
|
.layer(ElevationIndex::Background)
|
||||||
),
|
.into_any_element(),
|
||||||
],
|
),
|
||||||
),
|
single_example(
|
||||||
])
|
"With Alpha",
|
||||||
.into_any_element()
|
IconButton::new("alpha", IconName::Check)
|
||||||
|
.alpha(0.5)
|
||||||
|
.style(ButtonStyle::Filled)
|
||||||
|
.layer(ElevationIndex::Background)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,7 @@ pub enum ToggleButtonPosition {
|
||||||
Last,
|
Last,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(IntoElement, IntoComponent)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
#[component(scope = "Input")]
|
|
||||||
pub struct ToggleButton {
|
pub struct ToggleButton {
|
||||||
base: ButtonLike,
|
base: ButtonLike,
|
||||||
position_in_group: Option<ToggleButtonPosition>,
|
position_in_group: Option<ToggleButtonPosition>,
|
||||||
|
@ -155,129 +154,139 @@ impl RenderOnce for ToggleButton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentPreview for ToggleButton {
|
impl Component for ToggleButton {
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
fn scope() -> ComponentScope {
|
||||||
v_flex()
|
ComponentScope::Input
|
||||||
.gap_6()
|
}
|
||||||
.children(vec![
|
|
||||||
example_group_with_title(
|
fn sort_name() -> &'static str {
|
||||||
"Button Styles",
|
"ButtonC"
|
||||||
vec![
|
}
|
||||||
single_example(
|
|
||||||
"Off",
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
ToggleButton::new("off", "Off")
|
Some(
|
||||||
.layer(ElevationIndex::Background)
|
v_flex()
|
||||||
.style(ButtonStyle::Filled)
|
.gap_6()
|
||||||
.into_any_element(),
|
.children(vec![
|
||||||
),
|
example_group_with_title(
|
||||||
single_example(
|
"Button Styles",
|
||||||
"On",
|
vec![
|
||||||
ToggleButton::new("on", "On")
|
single_example(
|
||||||
.layer(ElevationIndex::Background)
|
"Off",
|
||||||
.toggle_state(true)
|
ToggleButton::new("off", "Off")
|
||||||
.style(ButtonStyle::Filled)
|
.layer(ElevationIndex::Background)
|
||||||
.into_any_element(),
|
.style(ButtonStyle::Filled)
|
||||||
),
|
.into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"Off – Disabled",
|
single_example(
|
||||||
ToggleButton::new("disabled_off", "Disabled Off")
|
"On",
|
||||||
.layer(ElevationIndex::Background)
|
ToggleButton::new("on", "On")
|
||||||
.disabled(true)
|
.layer(ElevationIndex::Background)
|
||||||
.style(ButtonStyle::Filled)
|
.toggle_state(true)
|
||||||
.into_any_element(),
|
.style(ButtonStyle::Filled)
|
||||||
),
|
.into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"On – Disabled",
|
single_example(
|
||||||
ToggleButton::new("disabled_on", "Disabled On")
|
"Off – Disabled",
|
||||||
.layer(ElevationIndex::Background)
|
ToggleButton::new("disabled_off", "Disabled Off")
|
||||||
.disabled(true)
|
.layer(ElevationIndex::Background)
|
||||||
.toggle_state(true)
|
.disabled(true)
|
||||||
.style(ButtonStyle::Filled)
|
.style(ButtonStyle::Filled)
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
),
|
),
|
||||||
],
|
single_example(
|
||||||
),
|
"On – Disabled",
|
||||||
example_group_with_title(
|
ToggleButton::new("disabled_on", "Disabled On")
|
||||||
"Button Group",
|
.layer(ElevationIndex::Background)
|
||||||
vec![
|
.disabled(true)
|
||||||
single_example(
|
.toggle_state(true)
|
||||||
"Three Buttons",
|
.style(ButtonStyle::Filled)
|
||||||
h_flex()
|
.into_any_element(),
|
||||||
.child(
|
),
|
||||||
ToggleButton::new("three_btn_first", "First")
|
],
|
||||||
.layer(ElevationIndex::Background)
|
),
|
||||||
.style(ButtonStyle::Filled)
|
example_group_with_title(
|
||||||
.first()
|
"Button Group",
|
||||||
.into_any_element(),
|
vec![
|
||||||
)
|
single_example(
|
||||||
.child(
|
"Three Buttons",
|
||||||
ToggleButton::new("three_btn_middle", "Middle")
|
h_flex()
|
||||||
.layer(ElevationIndex::Background)
|
.child(
|
||||||
.style(ButtonStyle::Filled)
|
ToggleButton::new("three_btn_first", "First")
|
||||||
.middle()
|
.layer(ElevationIndex::Background)
|
||||||
.toggle_state(true)
|
.style(ButtonStyle::Filled)
|
||||||
.into_any_element(),
|
.first()
|
||||||
)
|
.into_any_element(),
|
||||||
.child(
|
)
|
||||||
ToggleButton::new("three_btn_last", "Last")
|
.child(
|
||||||
.layer(ElevationIndex::Background)
|
ToggleButton::new("three_btn_middle", "Middle")
|
||||||
.style(ButtonStyle::Filled)
|
.layer(ElevationIndex::Background)
|
||||||
.last()
|
.style(ButtonStyle::Filled)
|
||||||
.into_any_element(),
|
.middle()
|
||||||
)
|
.toggle_state(true)
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
),
|
)
|
||||||
single_example(
|
.child(
|
||||||
"Two Buttons",
|
ToggleButton::new("three_btn_last", "Last")
|
||||||
h_flex()
|
.layer(ElevationIndex::Background)
|
||||||
.child(
|
.style(ButtonStyle::Filled)
|
||||||
ToggleButton::new("two_btn_first", "First")
|
.last()
|
||||||
.layer(ElevationIndex::Background)
|
.into_any_element(),
|
||||||
.style(ButtonStyle::Filled)
|
)
|
||||||
.first()
|
.into_any_element(),
|
||||||
.into_any_element(),
|
),
|
||||||
)
|
single_example(
|
||||||
.child(
|
"Two Buttons",
|
||||||
ToggleButton::new("two_btn_last", "Last")
|
h_flex()
|
||||||
.layer(ElevationIndex::Background)
|
.child(
|
||||||
.style(ButtonStyle::Filled)
|
ToggleButton::new("two_btn_first", "First")
|
||||||
.last()
|
.layer(ElevationIndex::Background)
|
||||||
.into_any_element(),
|
.style(ButtonStyle::Filled)
|
||||||
)
|
.first()
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
),
|
)
|
||||||
],
|
.child(
|
||||||
),
|
ToggleButton::new("two_btn_last", "Last")
|
||||||
example_group_with_title(
|
.layer(ElevationIndex::Background)
|
||||||
"Alternate Sizes",
|
.style(ButtonStyle::Filled)
|
||||||
vec![
|
.last()
|
||||||
single_example(
|
.into_any_element(),
|
||||||
"None",
|
)
|
||||||
ToggleButton::new("none", "None")
|
.into_any_element(),
|
||||||
.layer(ElevationIndex::Background)
|
),
|
||||||
.style(ButtonStyle::Filled)
|
],
|
||||||
.size(ButtonSize::None)
|
),
|
||||||
.into_any_element(),
|
example_group_with_title(
|
||||||
),
|
"Alternate Sizes",
|
||||||
single_example(
|
vec![
|
||||||
"Compact",
|
single_example(
|
||||||
ToggleButton::new("compact", "Compact")
|
"None",
|
||||||
.layer(ElevationIndex::Background)
|
ToggleButton::new("none", "None")
|
||||||
.style(ButtonStyle::Filled)
|
.layer(ElevationIndex::Background)
|
||||||
.size(ButtonSize::Compact)
|
.style(ButtonStyle::Filled)
|
||||||
.into_any_element(),
|
.size(ButtonSize::None)
|
||||||
),
|
.into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"Large",
|
single_example(
|
||||||
ToggleButton::new("large", "Large")
|
"Compact",
|
||||||
.layer(ElevationIndex::Background)
|
ToggleButton::new("compact", "Compact")
|
||||||
.style(ButtonStyle::Filled)
|
.layer(ElevationIndex::Background)
|
||||||
.size(ButtonSize::Large)
|
.style(ButtonStyle::Filled)
|
||||||
.into_any_element(),
|
.size(ButtonSize::Compact)
|
||||||
),
|
.into_any_element(),
|
||||||
],
|
),
|
||||||
),
|
single_example(
|
||||||
])
|
"Large",
|
||||||
.into_any_element()
|
ToggleButton::new("large", "Large")
|
||||||
|
.layer(ElevationIndex::Background)
|
||||||
|
.style(ButtonStyle::Filled)
|
||||||
|
.size(ButtonSize::Large)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
use crate::component_prelude::*;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use component::{ComponentPreview, example_group, single_example};
|
|
||||||
use gpui::{AnyElement, IntoElement, ParentElement, StyleRefinement, Styled};
|
use gpui::{AnyElement, IntoElement, ParentElement, StyleRefinement, Styled};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
|
@ -23,8 +23,7 @@ pub fn h_container() -> ContentGroup {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A flexible container component that can hold other elements.
|
/// A flexible container component that can hold other elements.
|
||||||
#[derive(IntoElement, IntoComponent)]
|
#[derive(IntoElement, Documented, RegisterComponent)]
|
||||||
#[component(scope = "Layout")]
|
|
||||||
pub struct ContentGroup {
|
pub struct ContentGroup {
|
||||||
base: Div,
|
base: Div,
|
||||||
border: bool,
|
border: bool,
|
||||||
|
@ -83,51 +82,56 @@ impl RenderOnce for ContentGroup {
|
||||||
this.border_1().border_color(cx.theme().colors().border)
|
this.border_1().border_color(cx.theme().colors().border)
|
||||||
})
|
})
|
||||||
.rounded_sm()
|
.rounded_sm()
|
||||||
.p_2()
|
|
||||||
.children(self.children)
|
.children(self.children)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// View this component preview using `workspace: open component-preview`
|
impl Component for ContentGroup {
|
||||||
impl ComponentPreview for ContentGroup {
|
fn scope() -> ComponentScope {
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
ComponentScope::Layout
|
||||||
example_group(vec![
|
}
|
||||||
single_example(
|
|
||||||
"Default",
|
fn description() -> Option<&'static str> {
|
||||||
ContentGroup::new()
|
Some(ContentGroup::DOCS)
|
||||||
.flex_1()
|
}
|
||||||
.items_center()
|
|
||||||
.justify_center()
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
.h_48()
|
Some(
|
||||||
.child(Label::new("Default ContentBox"))
|
example_group(vec![
|
||||||
.into_any_element(),
|
single_example(
|
||||||
)
|
"Default",
|
||||||
.grow(),
|
ContentGroup::new()
|
||||||
single_example(
|
.flex_1()
|
||||||
"Without Border",
|
.items_center()
|
||||||
ContentGroup::new()
|
.justify_center()
|
||||||
.flex_1()
|
.h_48()
|
||||||
.items_center()
|
.child(Label::new("Default ContentGroup"))
|
||||||
.justify_center()
|
.into_any_element(),
|
||||||
.h_48()
|
).description("A contained style for laying out groups of content. Has a default background and border color."),
|
||||||
.borderless()
|
single_example(
|
||||||
.child(Label::new("Borderless ContentBox"))
|
"Without Border",
|
||||||
.into_any_element(),
|
ContentGroup::new()
|
||||||
)
|
.flex_1()
|
||||||
.grow(),
|
.items_center()
|
||||||
single_example(
|
.justify_center()
|
||||||
"Without Fill",
|
.h_48()
|
||||||
ContentGroup::new()
|
.borderless()
|
||||||
.flex_1()
|
.child(Label::new("Borderless ContentGroup"))
|
||||||
.items_center()
|
.into_any_element(),
|
||||||
.justify_center()
|
),
|
||||||
.h_48()
|
single_example(
|
||||||
.unfilled()
|
"Without Fill",
|
||||||
.child(Label::new("Unfilled ContentBox"))
|
ContentGroup::new()
|
||||||
.into_any_element(),
|
.flex_1()
|
||||||
)
|
.items_center()
|
||||||
.grow(),
|
.justify_center()
|
||||||
])
|
.h_48()
|
||||||
.into_any_element()
|
.unfilled()
|
||||||
|
.child(Label::new("Unfilled ContentGroup"))
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use gpui::{ClickEvent, CursorStyle};
|
||||||
|
|
||||||
use crate::{Color, IconButton, IconButtonShape, IconName, IconSize, prelude::*};
|
use crate::{Color, IconButton, IconButtonShape, IconName, IconSize, prelude::*};
|
||||||
|
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub struct Disclosure {
|
pub struct Disclosure {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
is_open: bool,
|
is_open: bool,
|
||||||
|
@ -84,3 +84,55 @@ impl RenderOnce for Disclosure {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Component for Disclosure {
|
||||||
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::Navigation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some(
|
||||||
|
"An interactive element used to show or hide content, typically used in expandable sections or tree-like structures.",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
|
Some(
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.children(vec![
|
||||||
|
example_group_with_title(
|
||||||
|
"Disclosure States",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Closed",
|
||||||
|
Disclosure::new("closed", false).into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Open",
|
||||||
|
Disclosure::new("open", true).into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Interactive Example",
|
||||||
|
vec![single_example(
|
||||||
|
"Toggleable",
|
||||||
|
v_flex()
|
||||||
|
.gap_2()
|
||||||
|
.child(
|
||||||
|
Disclosure::new("interactive", false)
|
||||||
|
// .on_toggle(Some(Arc::new(|_, _, cx| {
|
||||||
|
// cx.refresh();
|
||||||
|
// })))
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
.child(Label::new("Click to toggle"))
|
||||||
|
.into_any_element(),
|
||||||
|
)],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ impl DividerColor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub struct Divider {
|
pub struct Divider {
|
||||||
style: DividerStyle,
|
style: DividerStyle,
|
||||||
direction: DividerDirection,
|
direction: DividerDirection,
|
||||||
|
@ -158,3 +158,90 @@ impl Divider {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Component for Divider {
|
||||||
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::Layout
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some(
|
||||||
|
"Visual separator used to create divisions between groups of content or sections in a layout.",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
|
Some(
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.children(vec![
|
||||||
|
example_group_with_title(
|
||||||
|
"Horizontal Dividers",
|
||||||
|
vec![
|
||||||
|
single_example("Default", Divider::horizontal().into_any_element()),
|
||||||
|
single_example(
|
||||||
|
"Border Color",
|
||||||
|
Divider::horizontal()
|
||||||
|
.color(DividerColor::Border)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Inset",
|
||||||
|
Divider::horizontal().inset().into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Dashed",
|
||||||
|
Divider::horizontal_dashed().into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Vertical Dividers",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Default",
|
||||||
|
div().h_16().child(Divider::vertical()).into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Border Color",
|
||||||
|
div()
|
||||||
|
.h_16()
|
||||||
|
.child(Divider::vertical().color(DividerColor::Border))
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Inset",
|
||||||
|
div()
|
||||||
|
.h_16()
|
||||||
|
.child(Divider::vertical().inset())
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Dashed",
|
||||||
|
div()
|
||||||
|
.h_16()
|
||||||
|
.child(Divider::vertical_dashed())
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Example Usage",
|
||||||
|
vec![single_example(
|
||||||
|
"Between Content",
|
||||||
|
v_flex()
|
||||||
|
.gap_4()
|
||||||
|
.px_4()
|
||||||
|
.child(Label::new("Section One"))
|
||||||
|
.child(Divider::horizontal())
|
||||||
|
.child(Label::new("Section Two"))
|
||||||
|
.child(Divider::horizontal_dashed())
|
||||||
|
.child(Label::new("Section Three"))
|
||||||
|
.into_any_element(),
|
||||||
|
)],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ enum LabelKind {
|
||||||
Element(AnyElement),
|
Element(AnyElement),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub struct DropdownMenu {
|
pub struct DropdownMenu {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
label: LabelKind,
|
label: LabelKind,
|
||||||
|
@ -72,6 +72,69 @@ impl RenderOnce for DropdownMenu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Component for DropdownMenu {
|
||||||
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::Input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"DropdownMenu"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some(
|
||||||
|
"A dropdown menu displays a list of actions or options. A dropdown menu is always activated by clicking a trigger (or via a keybinding).",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(window: &mut Window, cx: &mut App) -> Option<AnyElement> {
|
||||||
|
let menu = ContextMenu::build(window, cx, |this, _, _| {
|
||||||
|
this.entry("Option 1", None, |_, _| {})
|
||||||
|
.entry("Option 2", None, |_, _| {})
|
||||||
|
.entry("Option 3", None, |_, _| {})
|
||||||
|
.separator()
|
||||||
|
.entry("Option 4", None, |_, _| {})
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.children(vec![
|
||||||
|
example_group_with_title(
|
||||||
|
"Basic Usage",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Default",
|
||||||
|
DropdownMenu::new("default", "Select an option", menu.clone())
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Full Width",
|
||||||
|
DropdownMenu::new(
|
||||||
|
"full-width",
|
||||||
|
"Full Width Dropdown",
|
||||||
|
menu.clone(),
|
||||||
|
)
|
||||||
|
.full_width(true)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"States",
|
||||||
|
vec![single_example(
|
||||||
|
"Disabled",
|
||||||
|
DropdownMenu::new("disabled", "Disabled Dropdown", menu.clone())
|
||||||
|
.disabled(true)
|
||||||
|
.into_any_element(),
|
||||||
|
)],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
struct DropdownMenuTrigger {
|
struct DropdownMenuTrigger {
|
||||||
label: LabelKind,
|
label: LabelKind,
|
||||||
|
|
|
@ -1,13 +1,31 @@
|
||||||
use crate::{Avatar, prelude::*};
|
use crate::component_prelude::*;
|
||||||
|
use crate::prelude::*;
|
||||||
use gpui::{AnyElement, StyleRefinement};
|
use gpui::{AnyElement, StyleRefinement};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
/// A facepile is a collection of faces stacked horizontally–
|
use super::Avatar;
|
||||||
/// always with the leftmost face on top and descending in z-index
|
|
||||||
|
/// An element that displays a collection of (usually) faces stacked
|
||||||
|
/// horizontally, with the left-most face on top, visually descending
|
||||||
|
/// from left to right.
|
||||||
///
|
///
|
||||||
/// Facepiles are used to display a group of people or things,
|
/// Facepiles are used to display a group of people or things,
|
||||||
/// such as a list of participants in a collaboration session.
|
/// such as a list of participants in a collaboration session.
|
||||||
#[derive(IntoElement, IntoComponent)]
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ## Default
|
||||||
|
///
|
||||||
|
/// A default, horizontal facepile.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use ui::{Avatar, Facepile, EXAMPLE_FACES};
|
||||||
|
///
|
||||||
|
/// Facepile::new(
|
||||||
|
/// EXAMPLE_FACES.iter().take(3).iter().map(|&url|
|
||||||
|
/// Avatar::new(url).into_any_element()).collect())
|
||||||
|
/// ```
|
||||||
|
#[derive(IntoElement, Documented, RegisterComponent)]
|
||||||
pub struct Facepile {
|
pub struct Facepile {
|
||||||
base: Div,
|
base: Div,
|
||||||
faces: SmallVec<[AnyElement; 2]>,
|
faces: SmallVec<[AnyElement; 2]>,
|
||||||
|
@ -60,27 +78,37 @@ impl RenderOnce for Facepile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentPreview for Facepile {
|
pub const EXAMPLE_FACES: [&'static str; 6] = [
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
"https://avatars.githubusercontent.com/u/326587?s=60&v=4",
|
||||||
let faces: [&'static str; 6] = [
|
"https://avatars.githubusercontent.com/u/2280405?s=60&v=4",
|
||||||
"https://avatars.githubusercontent.com/u/326587?s=60&v=4",
|
"https://avatars.githubusercontent.com/u/1789?s=60&v=4",
|
||||||
"https://avatars.githubusercontent.com/u/2280405?s=60&v=4",
|
"https://avatars.githubusercontent.com/u/67129314?s=60&v=4",
|
||||||
"https://avatars.githubusercontent.com/u/1789?s=60&v=4",
|
"https://avatars.githubusercontent.com/u/482957?s=60&v=4",
|
||||||
"https://avatars.githubusercontent.com/u/67129314?s=60&v=4",
|
"https://avatars.githubusercontent.com/u/1714999?s=60&v=4",
|
||||||
"https://avatars.githubusercontent.com/u/482957?s=60&v=4",
|
];
|
||||||
"https://avatars.githubusercontent.com/u/1714999?s=60&v=4",
|
|
||||||
];
|
|
||||||
|
|
||||||
v_flex()
|
impl Component for Facepile {
|
||||||
.gap_6()
|
fn scope() -> ComponentScope {
|
||||||
.children(vec![
|
ComponentScope::Collaboration
|
||||||
example_group_with_title(
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some(
|
||||||
|
"Displays a collection of avatars or initials in a compact format. Often used to represent active collaborators or a subset of contributors.",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
|
Some(
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.children(vec![example_group_with_title(
|
||||||
"Facepile Examples",
|
"Facepile Examples",
|
||||||
vec![
|
vec![
|
||||||
single_example(
|
single_example(
|
||||||
"Default",
|
"Default",
|
||||||
Facepile::new(
|
Facepile::new(
|
||||||
faces
|
EXAMPLE_FACES
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&url| Avatar::new(url).into_any_element())
|
.map(|&url| Avatar::new(url).into_any_element())
|
||||||
.collect(),
|
.collect(),
|
||||||
|
@ -90,7 +118,7 @@ impl ComponentPreview for Facepile {
|
||||||
single_example(
|
single_example(
|
||||||
"Custom Size",
|
"Custom Size",
|
||||||
Facepile::new(
|
Facepile::new(
|
||||||
faces
|
EXAMPLE_FACES
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&url| Avatar::new(url).size(px(24.)).into_any_element())
|
.map(|&url| Avatar::new(url).size(px(24.)).into_any_element())
|
||||||
.collect(),
|
.collect(),
|
||||||
|
@ -98,19 +126,8 @@ impl ComponentPreview for Facepile {
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
)])
|
||||||
example_group_with_title(
|
.into_any_element(),
|
||||||
"Special Cases",
|
)
|
||||||
vec![
|
|
||||||
single_example("Empty Facepile", Facepile::empty().into_any_element()),
|
|
||||||
single_example(
|
|
||||||
"Single Face",
|
|
||||||
Facepile::new(vec![Avatar::new(faces[0]).into_any_element()].into())
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
])
|
|
||||||
.into_any_element()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,7 +136,7 @@ impl IconSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(IntoElement, IntoComponent)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub struct Icon {
|
pub struct Icon {
|
||||||
source: IconSource,
|
source: IconSource,
|
||||||
color: Color,
|
color: Color,
|
||||||
|
@ -265,43 +265,54 @@ impl RenderOnce for IconWithIndicator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// View this component preview using `workspace: open component-preview`
|
impl Component for Icon {
|
||||||
impl ComponentPreview for Icon {
|
fn scope() -> ComponentScope {
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
ComponentScope::None
|
||||||
v_flex()
|
}
|
||||||
.gap_6()
|
|
||||||
.children(vec![
|
fn description() -> Option<&'static str> {
|
||||||
example_group_with_title(
|
Some(
|
||||||
"Sizes",
|
"A versatile icon component that supports SVG and image-based icons with customizable size, color, and transformations.",
|
||||||
vec![
|
)
|
||||||
single_example("Default", Icon::new(IconName::Star).into_any_element()),
|
}
|
||||||
single_example(
|
|
||||||
"Small",
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
Icon::new(IconName::Star)
|
Some(
|
||||||
.size(IconSize::Small)
|
v_flex()
|
||||||
.into_any_element(),
|
.gap_6()
|
||||||
),
|
.children(vec![
|
||||||
single_example(
|
example_group_with_title(
|
||||||
"Large",
|
"Sizes",
|
||||||
Icon::new(IconName::Star)
|
vec![
|
||||||
.size(IconSize::XLarge)
|
single_example("Default", Icon::new(IconName::Star).into_any_element()),
|
||||||
.into_any_element(),
|
single_example(
|
||||||
),
|
"Small",
|
||||||
],
|
Icon::new(IconName::Star)
|
||||||
),
|
.size(IconSize::Small)
|
||||||
example_group_with_title(
|
.into_any_element(),
|
||||||
"Colors",
|
),
|
||||||
vec![
|
single_example(
|
||||||
single_example("Default", Icon::new(IconName::Bell).into_any_element()),
|
"Large",
|
||||||
single_example(
|
Icon::new(IconName::Star)
|
||||||
"Custom Color",
|
.size(IconSize::XLarge)
|
||||||
Icon::new(IconName::Bell)
|
.into_any_element(),
|
||||||
.color(Color::Error)
|
),
|
||||||
.into_any_element(),
|
],
|
||||||
),
|
),
|
||||||
],
|
example_group_with_title(
|
||||||
),
|
"Colors",
|
||||||
])
|
vec![
|
||||||
.into_any_element()
|
single_example("Default", Icon::new(IconName::Bell).into_any_element()),
|
||||||
|
single_example(
|
||||||
|
"Custom Color",
|
||||||
|
Icon::new(IconName::Bell)
|
||||||
|
.color(Color::Error)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use gpui::{AnyElement, IntoElement, Point};
|
||||||
|
|
||||||
use crate::{IconDecoration, IconDecorationKind, prelude::*};
|
use crate::{IconDecoration, IconDecorationKind, prelude::*};
|
||||||
|
|
||||||
#[derive(IntoElement, IntoComponent)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub struct DecoratedIcon {
|
pub struct DecoratedIcon {
|
||||||
icon: Icon,
|
icon: Icon,
|
||||||
decoration: Option<IconDecoration>,
|
decoration: Option<IconDecoration>,
|
||||||
|
@ -24,9 +24,18 @@ impl RenderOnce for DecoratedIcon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// View this component preview using `workspace: open component-preview`
|
impl Component for DecoratedIcon {
|
||||||
impl ComponentPreview for DecoratedIcon {
|
fn scope() -> ComponentScope {
|
||||||
fn preview(_window: &mut Window, cx: &mut App) -> AnyElement {
|
ComponentScope::None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some(
|
||||||
|
"An icon with an optional decoration overlay (like an X, triangle, or dot) that can be positioned relative to the icon",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, cx: &mut App) -> Option<AnyElement> {
|
||||||
let decoration_x = IconDecoration::new(
|
let decoration_x = IconDecoration::new(
|
||||||
IconDecorationKind::X,
|
IconDecorationKind::X,
|
||||||
cx.theme().colors().surface_background,
|
cx.theme().colors().surface_background,
|
||||||
|
@ -60,32 +69,38 @@ impl ComponentPreview for DecoratedIcon {
|
||||||
y: px(-2.),
|
y: px(-2.),
|
||||||
});
|
});
|
||||||
|
|
||||||
v_flex()
|
Some(
|
||||||
.gap_6()
|
v_flex()
|
||||||
.children(vec![example_group_with_title(
|
.gap_6()
|
||||||
"Decorations",
|
.children(vec![example_group_with_title(
|
||||||
vec![
|
"Decorations",
|
||||||
single_example(
|
vec![
|
||||||
"No Decoration",
|
single_example(
|
||||||
DecoratedIcon::new(Icon::new(IconName::FileDoc), None).into_any_element(),
|
"No Decoration",
|
||||||
),
|
DecoratedIcon::new(Icon::new(IconName::FileDoc), None)
|
||||||
single_example(
|
.into_any_element(),
|
||||||
"X Decoration",
|
),
|
||||||
DecoratedIcon::new(Icon::new(IconName::FileDoc), Some(decoration_x))
|
single_example(
|
||||||
|
"X Decoration",
|
||||||
|
DecoratedIcon::new(Icon::new(IconName::FileDoc), Some(decoration_x))
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Triangle Decoration",
|
||||||
|
DecoratedIcon::new(
|
||||||
|
Icon::new(IconName::FileDoc),
|
||||||
|
Some(decoration_triangle),
|
||||||
|
)
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
),
|
),
|
||||||
single_example(
|
single_example(
|
||||||
"Triangle Decoration",
|
"Dot Decoration",
|
||||||
DecoratedIcon::new(Icon::new(IconName::FileDoc), Some(decoration_triangle))
|
DecoratedIcon::new(Icon::new(IconName::FileDoc), Some(decoration_dot))
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
),
|
),
|
||||||
single_example(
|
],
|
||||||
"Dot Decoration",
|
)])
|
||||||
DecoratedIcon::new(Icon::new(IconName::FileDoc), Some(decoration_dot))
|
.into_any_element(),
|
||||||
.into_any_element(),
|
)
|
||||||
),
|
|
||||||
],
|
|
||||||
)])
|
|
||||||
.into_any_element()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ use strum::{EnumIter, EnumString, IntoStaticStr};
|
||||||
use ui_macros::{DerivePathStr, path_str};
|
use ui_macros::{DerivePathStr, path_str};
|
||||||
|
|
||||||
use crate::Color;
|
use crate::Color;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Debug,
|
Debug,
|
||||||
|
@ -30,7 +31,7 @@ pub enum VectorName {
|
||||||
/// A [`Vector`] is different from an [`crate::Icon`] in that it is intended
|
/// A [`Vector`] is different from an [`crate::Icon`] in that it is intended
|
||||||
/// to be displayed at a specific size, or series of sizes, rather
|
/// to be displayed at a specific size, or series of sizes, rather
|
||||||
/// than conforming to the standard size of an icon.
|
/// than conforming to the standard size of an icon.
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub struct Vector {
|
pub struct Vector {
|
||||||
path: &'static str,
|
path: &'static str,
|
||||||
color: Color,
|
color: Color,
|
||||||
|
@ -61,7 +62,6 @@ impl Vector {
|
||||||
/// Sets the vector size.
|
/// Sets the vector size.
|
||||||
pub fn size(mut self, size: impl Into<Size<Rems>>) -> Self {
|
pub fn size(mut self, size: impl Into<Size<Rems>>) -> Self {
|
||||||
let size = size.into();
|
let size = size.into();
|
||||||
|
|
||||||
self.size = size;
|
self.size = size;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -83,24 +83,72 @@ impl RenderOnce for Vector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "stories")]
|
impl Component for Vector {
|
||||||
pub mod story {
|
fn scope() -> ComponentScope {
|
||||||
use gpui::Render;
|
ComponentScope::Images
|
||||||
use story::{Story, StoryItem, StorySection};
|
}
|
||||||
use strum::IntoEnumIterator;
|
|
||||||
|
|
||||||
use crate::prelude::*;
|
fn name() -> &'static str {
|
||||||
|
"Vector"
|
||||||
|
}
|
||||||
|
|
||||||
use super::{Vector, VectorName};
|
fn description() -> Option<&'static str> {
|
||||||
|
Some("A vector image component that can be displayed at specific sizes.")
|
||||||
|
}
|
||||||
|
|
||||||
pub struct VectorStory;
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
|
Some(
|
||||||
impl Render for VectorStory {
|
v_flex()
|
||||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
.gap_6()
|
||||||
Story::container().child(StorySection::new().children(VectorName::iter().map(
|
.children(vec![
|
||||||
|vector| StoryItem::new(format!("{:?}", vector), Vector::square(vector, rems(8.))),
|
example_group_with_title(
|
||||||
)))
|
"Basic Usage",
|
||||||
}
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Default",
|
||||||
|
Vector::square(VectorName::ZedLogo, rems(8.)).into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Custom Size",
|
||||||
|
Vector::new(VectorName::ZedLogo, rems(12.), rems(6.))
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Colored",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Accent Color",
|
||||||
|
Vector::square(VectorName::ZedLogo, rems(8.))
|
||||||
|
.color(Color::Accent)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Error Color",
|
||||||
|
Vector::square(VectorName::ZedLogo, rems(8.))
|
||||||
|
.color(Color::Error)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Different Vectors",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Zed Logo",
|
||||||
|
Vector::square(VectorName::ZedLogo, rems(8.)).into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Zed X Copilot",
|
||||||
|
Vector::square(VectorName::ZedXCopilot, rems(8.))
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::{AnyIcon, prelude::*};
|
use super::AnyIcon;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
enum IndicatorKind {
|
enum IndicatorKind {
|
||||||
|
@ -8,7 +9,7 @@ enum IndicatorKind {
|
||||||
Icon(AnyIcon),
|
Icon(AnyIcon),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub struct Indicator {
|
pub struct Indicator {
|
||||||
kind: IndicatorKind,
|
kind: IndicatorKind,
|
||||||
border_color: Option<Color>,
|
border_color: Option<Color>,
|
||||||
|
@ -82,3 +83,95 @@ impl RenderOnce for Indicator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Component for Indicator {
|
||||||
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::Status
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some(
|
||||||
|
"Visual indicators used to represent status, notifications, or draw attention to specific elements.",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
|
Some(
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.children(vec![
|
||||||
|
example_group_with_title(
|
||||||
|
"Dot Indicators",
|
||||||
|
vec![
|
||||||
|
single_example("Default", Indicator::dot().into_any_element()),
|
||||||
|
single_example(
|
||||||
|
"Success",
|
||||||
|
Indicator::dot().color(Color::Success).into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Warning",
|
||||||
|
Indicator::dot().color(Color::Warning).into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Error",
|
||||||
|
Indicator::dot().color(Color::Error).into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"With Border",
|
||||||
|
Indicator::dot()
|
||||||
|
.color(Color::Accent)
|
||||||
|
.border_color(Color::Default)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Bar Indicators",
|
||||||
|
vec![
|
||||||
|
single_example("Default", Indicator::bar().into_any_element()),
|
||||||
|
single_example(
|
||||||
|
"Success",
|
||||||
|
Indicator::bar().color(Color::Success).into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Warning",
|
||||||
|
Indicator::bar().color(Color::Warning).into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Error",
|
||||||
|
Indicator::bar().color(Color::Error).into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Icon Indicators",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Default",
|
||||||
|
Indicator::icon(Icon::new(IconName::Circle)).into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Success",
|
||||||
|
Indicator::icon(Icon::new(IconName::Check))
|
||||||
|
.color(Color::Success)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Warning",
|
||||||
|
Indicator::icon(Icon::new(IconName::Warning))
|
||||||
|
.color(Color::Warning)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Error",
|
||||||
|
Indicator::icon(Icon::new(IconName::X))
|
||||||
|
.color(Color::Error)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use gpui::{
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
#[derive(Debug, IntoElement, Clone)]
|
#[derive(Debug, IntoElement, Clone, RegisterComponent)]
|
||||||
pub struct KeyBinding {
|
pub struct KeyBinding {
|
||||||
/// A keybinding consists of a key and a set of modifier keys.
|
/// A keybinding consists of a key and a set of modifier keys.
|
||||||
/// More then one keybinding produces a chord.
|
/// More then one keybinding produces a chord.
|
||||||
|
@ -449,6 +449,93 @@ fn keystroke_text(keystroke: &Keystroke, platform_style: PlatformStyle, vim_mode
|
||||||
text
|
text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Component for KeyBinding {
|
||||||
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::Input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"KeyBinding"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some(
|
||||||
|
"A component that displays a key binding, supporting different platform styles and vim mode.",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, cx: &mut App) -> Option<AnyElement> {
|
||||||
|
Some(
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.children(vec![
|
||||||
|
example_group_with_title(
|
||||||
|
"Basic Usage",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Default",
|
||||||
|
KeyBinding::new(
|
||||||
|
gpui::KeyBinding::new("ctrl-s", gpui::NoAction, None),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Mac Style",
|
||||||
|
KeyBinding::new(
|
||||||
|
gpui::KeyBinding::new("cmd-s", gpui::NoAction, None),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.platform_style(PlatformStyle::Mac)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Windows Style",
|
||||||
|
KeyBinding::new(
|
||||||
|
gpui::KeyBinding::new("ctrl-s", gpui::NoAction, None),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.platform_style(PlatformStyle::Windows)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Vim Mode",
|
||||||
|
vec![single_example(
|
||||||
|
"Vim Mode Enabled",
|
||||||
|
KeyBinding::new(gpui::KeyBinding::new("dd", gpui::NoAction, None), cx)
|
||||||
|
.vim_mode(true)
|
||||||
|
.into_any_element(),
|
||||||
|
)],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Complex Bindings",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Multiple Keys",
|
||||||
|
KeyBinding::new(
|
||||||
|
gpui::KeyBinding::new("ctrl-k ctrl-b", gpui::NoAction, None),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"With Shift",
|
||||||
|
KeyBinding::new(
|
||||||
|
gpui::KeyBinding::new("shift-cmd-p", gpui::NoAction, None),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -18,7 +18,7 @@ use theme::Appearance;
|
||||||
/// .prefix("Save:")
|
/// .prefix("Save:")
|
||||||
/// .size(Pixels::from(14.0));
|
/// .size(Pixels::from(14.0));
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, IntoElement, IntoComponent)]
|
#[derive(Debug, IntoElement, RegisterComponent)]
|
||||||
pub struct KeybindingHint {
|
pub struct KeybindingHint {
|
||||||
prefix: Option<SharedString>,
|
prefix: Option<SharedString>,
|
||||||
suffix: Option<SharedString>,
|
suffix: Option<SharedString>,
|
||||||
|
@ -205,68 +205,81 @@ impl RenderOnce for KeybindingHint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// View this component preview using `workspace: open component-preview`
|
impl Component for KeybindingHint {
|
||||||
impl ComponentPreview for KeybindingHint {
|
fn scope() -> ComponentScope {
|
||||||
fn preview(window: &mut Window, cx: &mut App) -> AnyElement {
|
ComponentScope::None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some("Displays a keyboard shortcut hint with optional prefix and suffix text")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(window: &mut Window, cx: &mut App) -> Option<AnyElement> {
|
||||||
let enter_fallback = gpui::KeyBinding::new("enter", menu::Confirm, None);
|
let enter_fallback = gpui::KeyBinding::new("enter", menu::Confirm, None);
|
||||||
let enter = KeyBinding::for_action(&menu::Confirm, window, cx)
|
let enter = KeyBinding::for_action(&menu::Confirm, window, cx)
|
||||||
.unwrap_or(KeyBinding::new(enter_fallback, cx));
|
.unwrap_or(KeyBinding::new(enter_fallback, cx));
|
||||||
|
|
||||||
let bg_color = cx.theme().colors().surface_background;
|
let bg_color = cx.theme().colors().surface_background;
|
||||||
|
|
||||||
v_flex()
|
Some(
|
||||||
.gap_6()
|
v_flex()
|
||||||
.children(vec![
|
.gap_6()
|
||||||
example_group_with_title(
|
.children(vec![
|
||||||
"Basic",
|
example_group_with_title(
|
||||||
vec![
|
"Basic",
|
||||||
single_example(
|
vec![
|
||||||
"With Prefix",
|
single_example(
|
||||||
KeybindingHint::with_prefix("Go to Start:", enter.clone(), bg_color)
|
"With Prefix",
|
||||||
|
KeybindingHint::with_prefix(
|
||||||
|
"Go to Start:",
|
||||||
|
enter.clone(),
|
||||||
|
bg_color,
|
||||||
|
)
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
),
|
),
|
||||||
single_example(
|
single_example(
|
||||||
"With Suffix",
|
"With Suffix",
|
||||||
KeybindingHint::with_suffix(enter.clone(), "Go to End", bg_color)
|
KeybindingHint::with_suffix(enter.clone(), "Go to End", bg_color)
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
),
|
),
|
||||||
single_example(
|
single_example(
|
||||||
"With Prefix and Suffix",
|
"With Prefix and Suffix",
|
||||||
KeybindingHint::new(enter.clone(), bg_color)
|
KeybindingHint::new(enter.clone(), bg_color)
|
||||||
.prefix("Confirm:")
|
.prefix("Confirm:")
|
||||||
.suffix("Execute selected action")
|
.suffix("Execute selected action")
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
example_group_with_title(
|
example_group_with_title(
|
||||||
"Sizes",
|
"Sizes",
|
||||||
vec![
|
vec![
|
||||||
single_example(
|
single_example(
|
||||||
"Small",
|
"Small",
|
||||||
KeybindingHint::new(enter.clone(), bg_color)
|
KeybindingHint::new(enter.clone(), bg_color)
|
||||||
.size(Pixels::from(12.0))
|
.size(Pixels::from(12.0))
|
||||||
.prefix("Small:")
|
.prefix("Small:")
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
),
|
),
|
||||||
single_example(
|
single_example(
|
||||||
"Medium",
|
"Medium",
|
||||||
KeybindingHint::new(enter.clone(), bg_color)
|
KeybindingHint::new(enter.clone(), bg_color)
|
||||||
.size(Pixels::from(16.0))
|
.size(Pixels::from(16.0))
|
||||||
.suffix("Medium")
|
.suffix("Medium")
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
),
|
),
|
||||||
single_example(
|
single_example(
|
||||||
"Large",
|
"Large",
|
||||||
KeybindingHint::new(enter.clone(), bg_color)
|
KeybindingHint::new(enter.clone(), bg_color)
|
||||||
.size(Pixels::from(20.0))
|
.size(Pixels::from(20.0))
|
||||||
.prefix("Large:")
|
.prefix("Large:")
|
||||||
.suffix("Size")
|
.suffix("Size")
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
.into_any_element()
|
.into_any_element(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use gpui::{FontWeight, HighlightStyle, StyledText};
|
||||||
|
|
||||||
use crate::{LabelCommon, LabelLike, LabelSize, LineHeightStyle, prelude::*};
|
use crate::{LabelCommon, LabelLike, LabelSize, LineHeightStyle, prelude::*};
|
||||||
|
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub struct HighlightedLabel {
|
pub struct HighlightedLabel {
|
||||||
base: LabelLike,
|
base: LabelLike,
|
||||||
label: SharedString,
|
label: SharedString,
|
||||||
|
@ -129,3 +129,99 @@ impl RenderOnce for HighlightedLabel {
|
||||||
.child(StyledText::new(self.label).with_default_highlights(&text_style, highlights))
|
.child(StyledText::new(self.label).with_default_highlights(&text_style, highlights))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Component for HighlightedLabel {
|
||||||
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::Typography
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"HighlightedLabel"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some("A label with highlighted characters based on specified indices.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
|
Some(
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.children(vec![
|
||||||
|
example_group_with_title(
|
||||||
|
"Basic Usage",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Default",
|
||||||
|
HighlightedLabel::new("Highlighted Text", vec![0, 1, 2, 3]).into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Custom Color",
|
||||||
|
HighlightedLabel::new("Colored Highlight", vec![0, 1, 7, 8, 9])
|
||||||
|
.color(Color::Accent)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Styles",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Bold",
|
||||||
|
HighlightedLabel::new("Bold Highlight", vec![0, 1, 2, 3])
|
||||||
|
.weight(FontWeight::BOLD)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Italic",
|
||||||
|
HighlightedLabel::new("Italic Highlight", vec![0, 1, 6, 7, 8])
|
||||||
|
.italic()
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Underline",
|
||||||
|
HighlightedLabel::new("Underlined Highlight", vec![0, 1, 10, 11, 12])
|
||||||
|
.underline()
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Sizes",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Small",
|
||||||
|
HighlightedLabel::new("Small Highlight", vec![0, 1, 5, 6, 7])
|
||||||
|
.size(LabelSize::Small)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Large",
|
||||||
|
HighlightedLabel::new("Large Highlight", vec![0, 1, 5, 6, 7])
|
||||||
|
.size(LabelSize::Large)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Special Cases",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Single Line",
|
||||||
|
HighlightedLabel::new("Single Line Highlight\nWith Newline", vec![0, 1, 7, 8, 9])
|
||||||
|
.single_line()
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Truncate",
|
||||||
|
HighlightedLabel::new("This is a very long text that should be truncated with highlights", vec![0, 1, 2, 3, 4, 5])
|
||||||
|
.truncate()
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ use gpui::StyleRefinement;
|
||||||
///
|
///
|
||||||
/// let my_label = Label::new("Deleted").strikethrough(true);
|
/// let my_label = Label::new("Deleted").strikethrough(true);
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(IntoElement, IntoComponent)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub struct Label {
|
pub struct Label {
|
||||||
base: LabelLike,
|
base: LabelLike,
|
||||||
label: SharedString,
|
label: SharedString,
|
||||||
|
@ -58,9 +58,6 @@ impl Label {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// nate: If we are going to do this, we might as well just
|
|
||||||
// impl Styled for Label and not constrain styles
|
|
||||||
|
|
||||||
// Style methods.
|
// Style methods.
|
||||||
impl Label {
|
impl Label {
|
||||||
fn style(&mut self) -> &mut StyleRefinement {
|
fn style(&mut self) -> &mut StyleRefinement {
|
||||||
|
@ -200,12 +197,17 @@ impl RenderOnce for Label {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod label_preview {
|
impl Component for Label {
|
||||||
use crate::prelude::*;
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::None
|
||||||
|
}
|
||||||
|
|
||||||
// View this component preview using `workspace: open component-preview`
|
fn description() -> Option<&'static str> {
|
||||||
impl ComponentPreview for Label {
|
Some("A text label component that supports various styles, sizes, and formatting options.")
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
|
Some(
|
||||||
v_flex()
|
v_flex()
|
||||||
.gap_6()
|
.gap_6()
|
||||||
.children(vec![
|
.children(vec![
|
||||||
|
@ -251,6 +253,6 @@ mod label_preview {
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,3 +232,70 @@ impl RenderOnce for LabelLike {
|
||||||
.children(self.children)
|
.children(self.children)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Component for LabelLike {
|
||||||
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::Typography
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"LabelLike"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some(
|
||||||
|
"A flexible, customizable label-like component that serves as a base for other label types.",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
|
Some(
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.children(vec![
|
||||||
|
example_group_with_title(
|
||||||
|
"Sizes",
|
||||||
|
vec![
|
||||||
|
single_example("Default", LabelLike::new().child("Default size").into_any_element()),
|
||||||
|
single_example("Large", LabelLike::new().size(LabelSize::Large).child("Large size").into_any_element()),
|
||||||
|
single_example("Small", LabelLike::new().size(LabelSize::Small).child("Small size").into_any_element()),
|
||||||
|
single_example("XSmall", LabelLike::new().size(LabelSize::XSmall).child("Extra small size").into_any_element()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Styles",
|
||||||
|
vec![
|
||||||
|
single_example("Bold", LabelLike::new().weight(FontWeight::BOLD).child("Bold text").into_any_element()),
|
||||||
|
single_example("Italic", LabelLike::new().italic().child("Italic text").into_any_element()),
|
||||||
|
single_example("Underline", LabelLike::new().underline().child("Underlined text").into_any_element()),
|
||||||
|
single_example("Strikethrough", LabelLike::new().strikethrough().child("Strikethrough text").into_any_element()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Colors",
|
||||||
|
vec![
|
||||||
|
single_example("Default", LabelLike::new().child("Default color").into_any_element()),
|
||||||
|
single_example("Accent", LabelLike::new().color(Color::Accent).child("Accent color").into_any_element()),
|
||||||
|
single_example("Error", LabelLike::new().color(Color::Error).child("Error color").into_any_element()),
|
||||||
|
single_example("Alpha", LabelLike::new().alpha(0.5).child("50% opacity").into_any_element()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Line Height",
|
||||||
|
vec![
|
||||||
|
single_example("Default", LabelLike::new().child("Default line height\nMulti-line text").into_any_element()),
|
||||||
|
single_example("UI Label", LabelLike::new().line_height_style(LineHeightStyle::UiLabel).child("UI label line height\nMulti-line text").into_any_element()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Special Cases",
|
||||||
|
vec![
|
||||||
|
single_example("Single Line", LabelLike::new().single_line().child("This is a very long text that should be displayed in a single line").into_any_element()),
|
||||||
|
single_example("Truncate", LabelLike::new().truncate().child("This is a very long text that should be truncated with an ellipsis").into_any_element()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,8 +2,7 @@ use crate::prelude::*;
|
||||||
use gpui::IntoElement;
|
use gpui::IntoElement;
|
||||||
use smallvec::{SmallVec, smallvec};
|
use smallvec::{SmallVec, smallvec};
|
||||||
|
|
||||||
#[derive(IntoElement, IntoComponent)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
#[component(scope = "Notification")]
|
|
||||||
pub struct AlertModal {
|
pub struct AlertModal {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
children: SmallVec<[AnyElement; 2]>,
|
children: SmallVec<[AnyElement; 2]>,
|
||||||
|
@ -77,23 +76,33 @@ impl ParentElement for AlertModal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentPreview for AlertModal {
|
impl Component for AlertModal {
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
fn scope() -> ComponentScope {
|
||||||
v_flex()
|
ComponentScope::Notification
|
||||||
.gap_6()
|
}
|
||||||
.p_4()
|
|
||||||
.children(vec![example_group(
|
fn description() -> Option<&'static str> {
|
||||||
vec![
|
Some("A modal dialog that presents an alert message with primary and dismiss actions.")
|
||||||
single_example(
|
}
|
||||||
"Basic Alert",
|
|
||||||
AlertModal::new("simple-modal", "Do you want to leave the current call?")
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
.child("The current window will be closed, and connections to any shared projects will be terminated."
|
Some(
|
||||||
)
|
v_flex()
|
||||||
.primary_action("Leave Call")
|
.gap_6()
|
||||||
.into_any_element(),
|
.p_4()
|
||||||
)
|
.children(vec![example_group(
|
||||||
],
|
vec![
|
||||||
)])
|
single_example(
|
||||||
.into_any_element()
|
"Basic Alert",
|
||||||
|
AlertModal::new("simple-modal", "Do you want to leave the current call?")
|
||||||
|
.child("The current window will be closed, and connections to any shared projects will be terminated."
|
||||||
|
)
|
||||||
|
.primary_action("Leave Call")
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)])
|
||||||
|
.into_any_element()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,9 @@ use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[derive(IntoElement)]
|
use super::Checkbox;
|
||||||
|
|
||||||
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub struct SettingsContainer {
|
pub struct SettingsContainer {
|
||||||
children: SmallVec<[AnyElement; 2]>,
|
children: SmallVec<[AnyElement; 2]>,
|
||||||
}
|
}
|
||||||
|
@ -33,3 +35,55 @@ impl RenderOnce for SettingsContainer {
|
||||||
v_flex().px_2().gap_1().children(self.children)
|
v_flex().px_2().gap_1().children(self.children)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Component for SettingsContainer {
|
||||||
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::Layout
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"SettingsContainer"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some("A container for organizing and displaying settings in a structured manner.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
|
Some(
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.children(vec![
|
||||||
|
example_group_with_title(
|
||||||
|
"Basic Usage",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Empty Container",
|
||||||
|
SettingsContainer::new().into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"With Content",
|
||||||
|
SettingsContainer::new()
|
||||||
|
.child(Label::new("Setting 1"))
|
||||||
|
.child(Label::new("Setting 2"))
|
||||||
|
.child(Label::new("Setting 3"))
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"With Different Elements",
|
||||||
|
vec![single_example(
|
||||||
|
"Mixed Content",
|
||||||
|
SettingsContainer::new()
|
||||||
|
.child(Label::new("Text Setting"))
|
||||||
|
.child(Checkbox::new("checkbox", ToggleState::Unselected))
|
||||||
|
.child(Button::new("button", "Click me"))
|
||||||
|
.into_any_element(),
|
||||||
|
)],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,8 +3,10 @@ use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{ListHeader, prelude::*};
|
use crate::{ListHeader, prelude::*};
|
||||||
|
|
||||||
|
use super::Checkbox;
|
||||||
|
|
||||||
/// A group of settings.
|
/// A group of settings.
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub struct SettingsGroup {
|
pub struct SettingsGroup {
|
||||||
header: SharedString,
|
header: SharedString,
|
||||||
children: SmallVec<[AnyElement; 2]>,
|
children: SmallVec<[AnyElement; 2]>,
|
||||||
|
@ -34,3 +36,75 @@ impl RenderOnce for SettingsGroup {
|
||||||
.children(self.children)
|
.children(self.children)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Component for SettingsGroup {
|
||||||
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::Layout
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"SettingsGroup"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some("A group of settings with a header, used to organize related settings.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
|
Some(
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.children(vec![
|
||||||
|
example_group_with_title(
|
||||||
|
"Basic Usage",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Empty Group",
|
||||||
|
SettingsGroup::new("General Settings").into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"With Children",
|
||||||
|
SettingsGroup::new("Appearance")
|
||||||
|
.child(
|
||||||
|
Checkbox::new("dark_mode", ToggleState::Unselected)
|
||||||
|
.label("Dark Mode"),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Checkbox::new("high_contrast", ToggleState::Unselected)
|
||||||
|
.label("High Contrast"),
|
||||||
|
)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Multiple Groups",
|
||||||
|
vec![single_example(
|
||||||
|
"Two Groups",
|
||||||
|
v_flex()
|
||||||
|
.gap_4()
|
||||||
|
.child(
|
||||||
|
SettingsGroup::new("General").child(
|
||||||
|
Checkbox::new("auto_update", ToggleState::Selected)
|
||||||
|
.label("Auto Update"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
SettingsGroup::new("Editor")
|
||||||
|
.child(
|
||||||
|
Checkbox::new("line_numbers", ToggleState::Selected)
|
||||||
|
.label("Show Line Numbers"),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Checkbox::new("word_wrap", ToggleState::Unselected)
|
||||||
|
.label("Word Wrap"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.into_any_element(),
|
||||||
|
)],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
mod context_menu;
|
mod context_menu;
|
||||||
mod disclosure;
|
|
||||||
mod icon;
|
|
||||||
mod icon_button;
|
mod icon_button;
|
||||||
mod keybinding;
|
mod keybinding;
|
||||||
mod list;
|
mod list;
|
||||||
|
@ -11,8 +9,6 @@ mod tab_bar;
|
||||||
mod toggle_button;
|
mod toggle_button;
|
||||||
|
|
||||||
pub use context_menu::*;
|
pub use context_menu::*;
|
||||||
pub use disclosure::*;
|
|
||||||
pub use icon::*;
|
|
||||||
pub use icon_button::*;
|
pub use icon_button::*;
|
||||||
pub use keybinding::*;
|
pub use keybinding::*;
|
||||||
pub use list::*;
|
pub use list::*;
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
use gpui::Render;
|
|
||||||
use story::Story;
|
|
||||||
use strum::IntoEnumIterator;
|
|
||||||
|
|
||||||
use crate::prelude::*;
|
|
||||||
use crate::{Icon, IconName};
|
|
||||||
|
|
||||||
pub struct IconStory;
|
|
||||||
|
|
||||||
impl Render for IconStory {
|
|
||||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
|
||||||
let icons = IconName::iter();
|
|
||||||
|
|
||||||
Story::container()
|
|
||||||
.child(Story::title_for::<Icon>())
|
|
||||||
.child(Story::label("DecoratedIcon"))
|
|
||||||
.child(Story::label("All Icons"))
|
|
||||||
.child(div().flex().gap_3().children(icons.map(Icon::new)))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -26,7 +26,7 @@ pub enum TabCloseSide {
|
||||||
End,
|
End,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(IntoElement, IntoComponent)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub struct Tab {
|
pub struct Tab {
|
||||||
div: Stateful<Div>,
|
div: Stateful<Div>,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
|
@ -171,48 +171,59 @@ impl RenderOnce for Tab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// View this component preview using `workspace: open component-preview`
|
impl Component for Tab {
|
||||||
impl ComponentPreview for Tab {
|
fn scope() -> ComponentScope {
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
ComponentScope::None
|
||||||
v_flex()
|
}
|
||||||
.gap_6()
|
|
||||||
.children(vec![example_group_with_title(
|
fn description() -> Option<&'static str> {
|
||||||
"Variations",
|
Some(
|
||||||
vec![
|
"A tab component that can be used in a tabbed interface, supporting different positions and states.",
|
||||||
single_example(
|
)
|
||||||
"Default",
|
}
|
||||||
Tab::new("default").child("Default Tab").into_any_element(),
|
|
||||||
),
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
single_example(
|
Some(
|
||||||
"Selected",
|
v_flex()
|
||||||
Tab::new("selected")
|
.gap_6()
|
||||||
.toggle_state(true)
|
.children(vec![example_group_with_title(
|
||||||
.child("Selected Tab")
|
"Variations",
|
||||||
.into_any_element(),
|
vec![
|
||||||
),
|
single_example(
|
||||||
single_example(
|
"Default",
|
||||||
"First",
|
Tab::new("default").child("Default Tab").into_any_element(),
|
||||||
Tab::new("first")
|
),
|
||||||
.position(TabPosition::First)
|
single_example(
|
||||||
.child("First Tab")
|
"Selected",
|
||||||
.into_any_element(),
|
Tab::new("selected")
|
||||||
),
|
.toggle_state(true)
|
||||||
single_example(
|
.child("Selected Tab")
|
||||||
"Middle",
|
.into_any_element(),
|
||||||
Tab::new("middle")
|
),
|
||||||
.position(TabPosition::Middle(Ordering::Equal))
|
single_example(
|
||||||
.child("Middle Tab")
|
"First",
|
||||||
.into_any_element(),
|
Tab::new("first")
|
||||||
),
|
.position(TabPosition::First)
|
||||||
single_example(
|
.child("First Tab")
|
||||||
"Last",
|
.into_any_element(),
|
||||||
Tab::new("last")
|
),
|
||||||
.position(TabPosition::Last)
|
single_example(
|
||||||
.child("Last Tab")
|
"Middle",
|
||||||
.into_any_element(),
|
Tab::new("middle")
|
||||||
),
|
.position(TabPosition::Middle(Ordering::Equal))
|
||||||
],
|
.child("Middle Tab")
|
||||||
)])
|
.into_any_element(),
|
||||||
.into_any_element()
|
),
|
||||||
|
single_example(
|
||||||
|
"Last",
|
||||||
|
Tab::new("last")
|
||||||
|
.position(TabPosition::Last)
|
||||||
|
.child("Last Tab")
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use smallvec::SmallVec;
|
||||||
use crate::Tab;
|
use crate::Tab;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub struct TabBar {
|
pub struct TabBar {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
start_children: SmallVec<[AnyElement; 2]>,
|
start_children: SmallVec<[AnyElement; 2]>,
|
||||||
|
@ -151,3 +151,57 @@ impl RenderOnce for TabBar {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Component for TabBar {
|
||||||
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::Navigation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"TabBar"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some("A horizontal bar containing tabs for navigation between different views or sections.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
|
Some(
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.children(vec![
|
||||||
|
example_group_with_title(
|
||||||
|
"Basic Usage",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Empty TabBar",
|
||||||
|
TabBar::new("empty_tab_bar").into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"With Tabs",
|
||||||
|
TabBar::new("tab_bar_with_tabs")
|
||||||
|
.child(Tab::new("tab1"))
|
||||||
|
.child(Tab::new("tab2"))
|
||||||
|
.child(Tab::new("tab3"))
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"With Start and End Children",
|
||||||
|
vec![single_example(
|
||||||
|
"Full TabBar",
|
||||||
|
TabBar::new("full_tab_bar")
|
||||||
|
.start_child(Button::new("start_button", "Start"))
|
||||||
|
.child(Tab::new("tab1"))
|
||||||
|
.child(Tab::new("tab2"))
|
||||||
|
.child(Tab::new("tab3"))
|
||||||
|
.end_child(Button::new("end_button", "End"))
|
||||||
|
.into_any_element(),
|
||||||
|
)],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::{Indicator, prelude::*};
|
||||||
use gpui::{AnyElement, FontWeight, IntoElement, Length, div};
|
use gpui::{AnyElement, FontWeight, IntoElement, Length, div};
|
||||||
|
|
||||||
/// A table component
|
/// A table component
|
||||||
#[derive(IntoElement, IntoComponent)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
column_headers: Vec<SharedString>,
|
column_headers: Vec<SharedString>,
|
||||||
rows: Vec<Vec<TableCell>>,
|
rows: Vec<Vec<TableCell>>,
|
||||||
|
@ -151,112 +151,121 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// View this component preview using `workspace: open component-preview`
|
impl Component for Table {
|
||||||
impl ComponentPreview for Table {
|
fn scope() -> ComponentScope {
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
ComponentScope::Layout
|
||||||
v_flex()
|
}
|
||||||
.gap_6()
|
|
||||||
.children(vec![
|
fn description() -> Option<&'static str> {
|
||||||
example_group_with_title(
|
Some("A table component for displaying data in rows and columns with optional styling.")
|
||||||
"Basic Tables",
|
}
|
||||||
vec![
|
|
||||||
single_example(
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
"Simple Table",
|
Some(
|
||||||
Table::new(vec!["Name", "Age", "City"])
|
v_flex()
|
||||||
.width(px(400.))
|
.gap_6()
|
||||||
.row(vec!["Alice", "28", "New York"])
|
.children(vec![
|
||||||
.row(vec!["Bob", "32", "San Francisco"])
|
example_group_with_title(
|
||||||
.row(vec!["Charlie", "25", "London"])
|
"Basic Tables",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Simple Table",
|
||||||
|
Table::new(vec!["Name", "Age", "City"])
|
||||||
|
.width(px(400.))
|
||||||
|
.row(vec!["Alice", "28", "New York"])
|
||||||
|
.row(vec!["Bob", "32", "San Francisco"])
|
||||||
|
.row(vec!["Charlie", "25", "London"])
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Two Column Table",
|
||||||
|
Table::new(vec!["Category", "Value"])
|
||||||
|
.width(px(300.))
|
||||||
|
.row(vec!["Revenue", "$100,000"])
|
||||||
|
.row(vec!["Expenses", "$75,000"])
|
||||||
|
.row(vec!["Profit", "$25,000"])
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Styled Tables",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Default",
|
||||||
|
Table::new(vec!["Product", "Price", "Stock"])
|
||||||
|
.width(px(400.))
|
||||||
|
.row(vec!["Laptop", "$999", "In Stock"])
|
||||||
|
.row(vec!["Phone", "$599", "Low Stock"])
|
||||||
|
.row(vec!["Tablet", "$399", "Out of Stock"])
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Striped",
|
||||||
|
Table::new(vec!["Product", "Price", "Stock"])
|
||||||
|
.width(px(400.))
|
||||||
|
.striped()
|
||||||
|
.row(vec!["Laptop", "$999", "In Stock"])
|
||||||
|
.row(vec!["Phone", "$599", "Low Stock"])
|
||||||
|
.row(vec!["Tablet", "$399", "Out of Stock"])
|
||||||
|
.row(vec!["Headphones", "$199", "In Stock"])
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Mixed Content Table",
|
||||||
|
vec![single_example(
|
||||||
|
"Table with Elements",
|
||||||
|
Table::new(vec!["Status", "Name", "Priority", "Deadline", "Action"])
|
||||||
|
.width(px(840.))
|
||||||
|
.row(vec![
|
||||||
|
element_cell(
|
||||||
|
Indicator::dot().color(Color::Success).into_any_element(),
|
||||||
|
),
|
||||||
|
string_cell("Project A"),
|
||||||
|
string_cell("High"),
|
||||||
|
string_cell("2023-12-31"),
|
||||||
|
element_cell(
|
||||||
|
Button::new("view_a", "View")
|
||||||
|
.style(ButtonStyle::Filled)
|
||||||
|
.full_width()
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.row(vec![
|
||||||
|
element_cell(
|
||||||
|
Indicator::dot().color(Color::Warning).into_any_element(),
|
||||||
|
),
|
||||||
|
string_cell("Project B"),
|
||||||
|
string_cell("Medium"),
|
||||||
|
string_cell("2024-03-15"),
|
||||||
|
element_cell(
|
||||||
|
Button::new("view_b", "View")
|
||||||
|
.style(ButtonStyle::Filled)
|
||||||
|
.full_width()
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.row(vec![
|
||||||
|
element_cell(
|
||||||
|
Indicator::dot().color(Color::Error).into_any_element(),
|
||||||
|
),
|
||||||
|
string_cell("Project C"),
|
||||||
|
string_cell("Low"),
|
||||||
|
string_cell("2024-06-30"),
|
||||||
|
element_cell(
|
||||||
|
Button::new("view_c", "View")
|
||||||
|
.style(ButtonStyle::Filled)
|
||||||
|
.full_width()
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
])
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
),
|
)],
|
||||||
single_example(
|
),
|
||||||
"Two Column Table",
|
])
|
||||||
Table::new(vec!["Category", "Value"])
|
.into_any_element(),
|
||||||
.width(px(300.))
|
)
|
||||||
.row(vec!["Revenue", "$100,000"])
|
|
||||||
.row(vec!["Expenses", "$75,000"])
|
|
||||||
.row(vec!["Profit", "$25,000"])
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
example_group_with_title(
|
|
||||||
"Styled Tables",
|
|
||||||
vec![
|
|
||||||
single_example(
|
|
||||||
"Default",
|
|
||||||
Table::new(vec!["Product", "Price", "Stock"])
|
|
||||||
.width(px(400.))
|
|
||||||
.row(vec!["Laptop", "$999", "In Stock"])
|
|
||||||
.row(vec!["Phone", "$599", "Low Stock"])
|
|
||||||
.row(vec!["Tablet", "$399", "Out of Stock"])
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
single_example(
|
|
||||||
"Striped",
|
|
||||||
Table::new(vec!["Product", "Price", "Stock"])
|
|
||||||
.width(px(400.))
|
|
||||||
.striped()
|
|
||||||
.row(vec!["Laptop", "$999", "In Stock"])
|
|
||||||
.row(vec!["Phone", "$599", "Low Stock"])
|
|
||||||
.row(vec!["Tablet", "$399", "Out of Stock"])
|
|
||||||
.row(vec!["Headphones", "$199", "In Stock"])
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
example_group_with_title(
|
|
||||||
"Mixed Content Table",
|
|
||||||
vec![single_example(
|
|
||||||
"Table with Elements",
|
|
||||||
Table::new(vec!["Status", "Name", "Priority", "Deadline", "Action"])
|
|
||||||
.width(px(840.))
|
|
||||||
.row(vec![
|
|
||||||
element_cell(
|
|
||||||
Indicator::dot().color(Color::Success).into_any_element(),
|
|
||||||
),
|
|
||||||
string_cell("Project A"),
|
|
||||||
string_cell("High"),
|
|
||||||
string_cell("2023-12-31"),
|
|
||||||
element_cell(
|
|
||||||
Button::new("view_a", "View")
|
|
||||||
.style(ButtonStyle::Filled)
|
|
||||||
.full_width()
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
])
|
|
||||||
.row(vec![
|
|
||||||
element_cell(
|
|
||||||
Indicator::dot().color(Color::Warning).into_any_element(),
|
|
||||||
),
|
|
||||||
string_cell("Project B"),
|
|
||||||
string_cell("Medium"),
|
|
||||||
string_cell("2024-03-15"),
|
|
||||||
element_cell(
|
|
||||||
Button::new("view_b", "View")
|
|
||||||
.style(ButtonStyle::Filled)
|
|
||||||
.full_width()
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
])
|
|
||||||
.row(vec![
|
|
||||||
element_cell(
|
|
||||||
Indicator::dot().color(Color::Error).into_any_element(),
|
|
||||||
),
|
|
||||||
string_cell("Project C"),
|
|
||||||
string_cell("Low"),
|
|
||||||
string_cell("2024-06-30"),
|
|
||||||
element_cell(
|
|
||||||
Button::new("view_c", "View")
|
|
||||||
.style(ButtonStyle::Filled)
|
|
||||||
.full_width()
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
])
|
|
||||||
.into_any_element(),
|
|
||||||
)],
|
|
||||||
),
|
|
||||||
])
|
|
||||||
.into_any_element()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,8 +38,7 @@ pub enum ToggleStyle {
|
||||||
/// Checkboxes are used for multiple choices, not for mutually exclusive choices.
|
/// Checkboxes are used for multiple choices, not for mutually exclusive choices.
|
||||||
/// Each checkbox works independently from other checkboxes in the list,
|
/// Each checkbox works independently from other checkboxes in the list,
|
||||||
/// therefore checking an additional box does not affect any other selections.
|
/// therefore checking an additional box does not affect any other selections.
|
||||||
#[derive(IntoElement, IntoComponent)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
#[component(scope = "Input")]
|
|
||||||
pub struct Checkbox {
|
pub struct Checkbox {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
toggle_state: ToggleState,
|
toggle_state: ToggleState,
|
||||||
|
@ -244,8 +243,7 @@ impl RenderOnce for Checkbox {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`Checkbox`] that has a [`Label`].
|
/// A [`Checkbox`] that has a [`Label`].
|
||||||
#[derive(IntoElement, IntoComponent)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
#[component(scope = "Input")]
|
|
||||||
pub struct CheckboxWithLabel {
|
pub struct CheckboxWithLabel {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
label: Label,
|
label: Label,
|
||||||
|
@ -344,8 +342,7 @@ impl RenderOnce for CheckboxWithLabel {
|
||||||
/// # Switch
|
/// # Switch
|
||||||
///
|
///
|
||||||
/// Switches are used to represent opposite states, such as enabled or disabled.
|
/// Switches are used to represent opposite states, such as enabled or disabled.
|
||||||
#[derive(IntoElement, IntoComponent)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
#[component(scope = "Input")]
|
|
||||||
pub struct Switch {
|
pub struct Switch {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
toggle_state: ToggleState,
|
toggle_state: ToggleState,
|
||||||
|
@ -479,7 +476,6 @@ impl RenderOnce for Switch {
|
||||||
|
|
||||||
/// A [`Switch`] that has a [`Label`].
|
/// A [`Switch`] that has a [`Label`].
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
// #[component(scope = "input")]
|
|
||||||
pub struct SwitchWithLabel {
|
pub struct SwitchWithLabel {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
label: Label,
|
label: Label,
|
||||||
|
@ -535,200 +531,232 @@ impl RenderOnce for SwitchWithLabel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// View this component preview using `workspace: open component-preview`
|
impl Component for Checkbox {
|
||||||
impl ComponentPreview for Checkbox {
|
fn scope() -> ComponentScope {
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
ComponentScope::Input
|
||||||
v_flex()
|
}
|
||||||
.gap_6()
|
|
||||||
.children(vec![
|
fn description() -> Option<&'static str> {
|
||||||
example_group_with_title(
|
Some("A checkbox component that can be used for multiple choice selections")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
|
Some(
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.children(vec![
|
||||||
|
example_group_with_title(
|
||||||
|
"States",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Unselected",
|
||||||
|
Checkbox::new("checkbox_unselected", ToggleState::Unselected)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Placeholder",
|
||||||
|
Checkbox::new("checkbox_indeterminate", ToggleState::Selected)
|
||||||
|
.placeholder(true)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Indeterminate",
|
||||||
|
Checkbox::new("checkbox_indeterminate", ToggleState::Indeterminate)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Selected",
|
||||||
|
Checkbox::new("checkbox_selected", ToggleState::Selected)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Styles",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Default",
|
||||||
|
Checkbox::new("checkbox_default", ToggleState::Selected)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Filled",
|
||||||
|
Checkbox::new("checkbox_filled", ToggleState::Selected)
|
||||||
|
.fill()
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"ElevationBased",
|
||||||
|
Checkbox::new("checkbox_elevation", ToggleState::Selected)
|
||||||
|
.style(ToggleStyle::ElevationBased(
|
||||||
|
ElevationIndex::EditorSurface,
|
||||||
|
))
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Custom Color",
|
||||||
|
Checkbox::new("checkbox_custom", ToggleState::Selected)
|
||||||
|
.style(ToggleStyle::Custom(hsla(142.0 / 360., 0.68, 0.45, 0.7)))
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Disabled",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Unselected",
|
||||||
|
Checkbox::new(
|
||||||
|
"checkbox_disabled_unselected",
|
||||||
|
ToggleState::Unselected,
|
||||||
|
)
|
||||||
|
.disabled(true)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Selected",
|
||||||
|
Checkbox::new("checkbox_disabled_selected", ToggleState::Selected)
|
||||||
|
.disabled(true)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"With Label",
|
||||||
|
vec![single_example(
|
||||||
|
"Default",
|
||||||
|
Checkbox::new("checkbox_with_label", ToggleState::Selected)
|
||||||
|
.label("Always save on quit")
|
||||||
|
.into_any_element(),
|
||||||
|
)],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for Switch {
|
||||||
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::Input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some("A switch component that represents binary states like on/off")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
|
Some(
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.children(vec![
|
||||||
|
example_group_with_title(
|
||||||
|
"States",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Off",
|
||||||
|
Switch::new("switch_off", ToggleState::Unselected)
|
||||||
|
.on_click(|_, _, _cx| {})
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"On",
|
||||||
|
Switch::new("switch_on", ToggleState::Selected)
|
||||||
|
.on_click(|_, _, _cx| {})
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Disabled",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Off",
|
||||||
|
Switch::new("switch_disabled_off", ToggleState::Unselected)
|
||||||
|
.disabled(true)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"On",
|
||||||
|
Switch::new("switch_disabled_on", ToggleState::Selected)
|
||||||
|
.disabled(true)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"With Label",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Label",
|
||||||
|
Switch::new("switch_with_label", ToggleState::Selected)
|
||||||
|
.label("Always save on quit")
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
// TODO: Where did theme_preview_keybinding go?
|
||||||
|
// single_example(
|
||||||
|
// "Keybinding",
|
||||||
|
// Switch::new("switch_with_keybinding", ToggleState::Selected)
|
||||||
|
// .key_binding(theme_preview_keybinding("cmd-shift-e"))
|
||||||
|
// .into_any_element(),
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for CheckboxWithLabel {
|
||||||
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::Input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some("A checkbox component with an attached label")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
|
Some(
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.children(vec![example_group_with_title(
|
||||||
"States",
|
"States",
|
||||||
vec![
|
vec![
|
||||||
single_example(
|
single_example(
|
||||||
"Unselected",
|
"Unselected",
|
||||||
Checkbox::new("checkbox_unselected", ToggleState::Unselected)
|
CheckboxWithLabel::new(
|
||||||
.into_any_element(),
|
"checkbox_with_label_unselected",
|
||||||
),
|
Label::new("Always save on quit"),
|
||||||
single_example(
|
ToggleState::Unselected,
|
||||||
"Placeholder",
|
|_, _, _| {},
|
||||||
Checkbox::new("checkbox_indeterminate", ToggleState::Selected)
|
)
|
||||||
.placeholder(true)
|
.into_any_element(),
|
||||||
.into_any_element(),
|
|
||||||
),
|
),
|
||||||
single_example(
|
single_example(
|
||||||
"Indeterminate",
|
"Indeterminate",
|
||||||
Checkbox::new("checkbox_indeterminate", ToggleState::Indeterminate)
|
CheckboxWithLabel::new(
|
||||||
.into_any_element(),
|
"checkbox_with_label_indeterminate",
|
||||||
),
|
Label::new("Always save on quit"),
|
||||||
single_example(
|
ToggleState::Indeterminate,
|
||||||
"Selected",
|
|_, _, _| {},
|
||||||
Checkbox::new("checkbox_selected", ToggleState::Selected)
|
)
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
example_group_with_title(
|
|
||||||
"Styles",
|
|
||||||
vec![
|
|
||||||
single_example(
|
|
||||||
"Default",
|
|
||||||
Checkbox::new("checkbox_default", ToggleState::Selected)
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
single_example(
|
|
||||||
"Filled",
|
|
||||||
Checkbox::new("checkbox_filled", ToggleState::Selected)
|
|
||||||
.fill()
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
single_example(
|
|
||||||
"ElevationBased",
|
|
||||||
Checkbox::new("checkbox_elevation", ToggleState::Selected)
|
|
||||||
.style(ToggleStyle::ElevationBased(ElevationIndex::EditorSurface))
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
single_example(
|
|
||||||
"Custom Color",
|
|
||||||
Checkbox::new("checkbox_custom", ToggleState::Selected)
|
|
||||||
.style(ToggleStyle::Custom(hsla(142.0 / 360., 0.68, 0.45, 0.7)))
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
example_group_with_title(
|
|
||||||
"Disabled",
|
|
||||||
vec![
|
|
||||||
single_example(
|
|
||||||
"Unselected",
|
|
||||||
Checkbox::new("checkbox_disabled_unselected", ToggleState::Unselected)
|
|
||||||
.disabled(true)
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
single_example(
|
|
||||||
"Selected",
|
|
||||||
Checkbox::new("checkbox_disabled_selected", ToggleState::Selected)
|
|
||||||
.disabled(true)
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
example_group_with_title(
|
|
||||||
"With Label",
|
|
||||||
vec![single_example(
|
|
||||||
"Default",
|
|
||||||
Checkbox::new("checkbox_with_label", ToggleState::Selected)
|
|
||||||
.label("Always save on quit")
|
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
)],
|
|
||||||
),
|
|
||||||
])
|
|
||||||
.into_any_element()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// View this component preview using `workspace: open component-preview`
|
|
||||||
impl ComponentPreview for Switch {
|
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
|
||||||
v_flex()
|
|
||||||
.gap_6()
|
|
||||||
.children(vec![
|
|
||||||
example_group_with_title(
|
|
||||||
"States",
|
|
||||||
vec![
|
|
||||||
single_example(
|
|
||||||
"Off",
|
|
||||||
Switch::new("switch_off", ToggleState::Unselected)
|
|
||||||
.on_click(|_, _, _cx| {})
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
),
|
||||||
single_example(
|
single_example(
|
||||||
"On",
|
"Selected",
|
||||||
Switch::new("switch_on", ToggleState::Selected)
|
CheckboxWithLabel::new(
|
||||||
.on_click(|_, _, _cx| {})
|
"checkbox_with_label_selected",
|
||||||
.into_any_element(),
|
Label::new("Always save on quit"),
|
||||||
|
ToggleState::Selected,
|
||||||
|
|_, _, _| {},
|
||||||
|
)
|
||||||
|
.into_any_element(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
)])
|
||||||
example_group_with_title(
|
.into_any_element(),
|
||||||
"Disabled",
|
)
|
||||||
vec![
|
|
||||||
single_example(
|
|
||||||
"Off",
|
|
||||||
Switch::new("switch_disabled_off", ToggleState::Unselected)
|
|
||||||
.disabled(true)
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
single_example(
|
|
||||||
"On",
|
|
||||||
Switch::new("switch_disabled_on", ToggleState::Selected)
|
|
||||||
.disabled(true)
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
example_group_with_title(
|
|
||||||
"With Label",
|
|
||||||
vec![
|
|
||||||
single_example(
|
|
||||||
"Label",
|
|
||||||
Switch::new("switch_with_label", ToggleState::Selected)
|
|
||||||
.label("Always save on quit")
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
// TODO: Where did theme_preview_keybinding go?
|
|
||||||
// single_example(
|
|
||||||
// "Keybinding",
|
|
||||||
// Switch::new("switch_with_keybinding", ToggleState::Selected)
|
|
||||||
// .key_binding(theme_preview_keybinding("cmd-shift-e"))
|
|
||||||
// .into_any_element(),
|
|
||||||
// ),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
])
|
|
||||||
.into_any_element()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// View this component preview using `workspace: open component-preview`
|
|
||||||
impl ComponentPreview for CheckboxWithLabel {
|
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
|
||||||
v_flex()
|
|
||||||
.gap_6()
|
|
||||||
.children(vec![example_group_with_title(
|
|
||||||
"States",
|
|
||||||
vec![
|
|
||||||
single_example(
|
|
||||||
"Unselected",
|
|
||||||
CheckboxWithLabel::new(
|
|
||||||
"checkbox_with_label_unselected",
|
|
||||||
Label::new("Always save on quit"),
|
|
||||||
ToggleState::Unselected,
|
|
||||||
|_, _, _| {},
|
|
||||||
)
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
single_example(
|
|
||||||
"Indeterminate",
|
|
||||||
CheckboxWithLabel::new(
|
|
||||||
"checkbox_with_label_indeterminate",
|
|
||||||
Label::new("Always save on quit"),
|
|
||||||
ToggleState::Indeterminate,
|
|
||||||
|_, _, _| {},
|
|
||||||
)
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
single_example(
|
|
||||||
"Selected",
|
|
||||||
CheckboxWithLabel::new(
|
|
||||||
"checkbox_with_label_selected",
|
|
||||||
Label::new("Always save on quit"),
|
|
||||||
ToggleState::Selected,
|
|
||||||
|_, _, _| {},
|
|
||||||
)
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)])
|
|
||||||
.into_any_element()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use theme::ThemeSettings;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::{Color, KeyBinding, Label, LabelSize, StyledExt, h_flex, v_flex};
|
use crate::{Color, KeyBinding, Label, LabelSize, StyledExt, h_flex, v_flex};
|
||||||
|
|
||||||
#[derive(IntoComponent)]
|
#[derive(RegisterComponent)]
|
||||||
pub struct Tooltip {
|
pub struct Tooltip {
|
||||||
title: SharedString,
|
title: SharedString,
|
||||||
meta: Option<SharedString>,
|
meta: Option<SharedString>,
|
||||||
|
@ -222,15 +222,26 @@ impl Render for LinkPreview {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// View this component preview using `workspace: open component-preview`
|
impl Component for Tooltip {
|
||||||
impl ComponentPreview for Tooltip {
|
fn scope() -> ComponentScope {
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
ComponentScope::None
|
||||||
example_group(vec![single_example(
|
}
|
||||||
"Text only",
|
|
||||||
Button::new("delete-example", "Delete")
|
fn description() -> Option<&'static str> {
|
||||||
.tooltip(Tooltip::text("This is a tooltip!"))
|
Some(
|
||||||
.into_any_element(),
|
"A tooltip that appears when hovering over an element, optionally showing a keybinding or additional metadata.",
|
||||||
)])
|
)
|
||||||
.into_any_element()
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
|
Some(
|
||||||
|
example_group(vec![single_example(
|
||||||
|
"Text only",
|
||||||
|
Button::new("delete-example", "Delete")
|
||||||
|
.tooltip(Tooltip::text("This is a tooltip!"))
|
||||||
|
.into_any_element(),
|
||||||
|
)])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,9 @@ pub use gpui::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use component::{
|
pub use component::{
|
||||||
ComponentPreview, ComponentScope, example_group, example_group_with_title, single_example,
|
Component, ComponentScope, example_group, example_group_with_title, single_example,
|
||||||
};
|
};
|
||||||
pub use ui_macros::IntoComponent;
|
pub use ui_macros::RegisterComponent;
|
||||||
|
|
||||||
pub use crate::DynamicSpacing;
|
pub use crate::DynamicSpacing;
|
||||||
pub use crate::animation::{AnimationDirection, AnimationDuration, DefaultAnimations};
|
pub use crate::animation::{AnimationDirection, AnimationDuration, DefaultAnimations};
|
||||||
|
|
|
@ -94,183 +94,192 @@ pub trait DefaultAnimations: Styled + Sized {
|
||||||
impl<E: Styled> DefaultAnimations for E {}
|
impl<E: Styled> DefaultAnimations for E {}
|
||||||
|
|
||||||
// Don't use this directly, it only exists to show animation previews
|
// Don't use this directly, it only exists to show animation previews
|
||||||
#[derive(IntoComponent)]
|
#[derive(RegisterComponent)]
|
||||||
struct Animation {}
|
struct Animation {}
|
||||||
|
|
||||||
// View this component preview using `workspace: open component-preview`
|
impl Component for Animation {
|
||||||
impl ComponentPreview for Animation {
|
fn scope() -> ComponentScope {
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
ComponentScope::None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some("Demonstrates various animation patterns and transitions available in the UI system.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
let container_size = 128.0;
|
let container_size = 128.0;
|
||||||
let element_size = 32.0;
|
let element_size = 32.0;
|
||||||
let left_offset = element_size - container_size / 2.0;
|
let left_offset = element_size - container_size / 2.0;
|
||||||
v_flex()
|
Some(
|
||||||
.gap_6()
|
v_flex()
|
||||||
.children(vec![
|
.gap_6()
|
||||||
example_group_with_title(
|
.children(vec![
|
||||||
"Animate In",
|
example_group_with_title(
|
||||||
vec![
|
"Animate In",
|
||||||
single_example(
|
vec![
|
||||||
"From Bottom",
|
single_example(
|
||||||
ContentGroup::new()
|
"From Bottom",
|
||||||
.relative()
|
ContentGroup::new()
|
||||||
.items_center()
|
.relative()
|
||||||
.justify_center()
|
.items_center()
|
||||||
.size(px(container_size))
|
.justify_center()
|
||||||
.child(
|
.size(px(container_size))
|
||||||
div()
|
.child(
|
||||||
.id("animate-in-from-bottom")
|
div()
|
||||||
.absolute()
|
.id("animate-in-from-bottom")
|
||||||
.size(px(element_size))
|
.absolute()
|
||||||
.left(px(left_offset))
|
.size(px(element_size))
|
||||||
.rounded_md()
|
.left(px(left_offset))
|
||||||
.bg(gpui::red())
|
.rounded_md()
|
||||||
.animate_in(AnimationDirection::FromBottom, false),
|
.bg(gpui::red())
|
||||||
)
|
.animate_in(AnimationDirection::FromBottom, false),
|
||||||
.into_any_element(),
|
)
|
||||||
),
|
.into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"From Top",
|
single_example(
|
||||||
ContentGroup::new()
|
"From Top",
|
||||||
.relative()
|
ContentGroup::new()
|
||||||
.items_center()
|
.relative()
|
||||||
.justify_center()
|
.items_center()
|
||||||
.size(px(container_size))
|
.justify_center()
|
||||||
.child(
|
.size(px(container_size))
|
||||||
div()
|
.child(
|
||||||
.id("animate-in-from-top")
|
div()
|
||||||
.absolute()
|
.id("animate-in-from-top")
|
||||||
.size(px(element_size))
|
.absolute()
|
||||||
.left(px(left_offset))
|
.size(px(element_size))
|
||||||
.rounded_md()
|
.left(px(left_offset))
|
||||||
.bg(gpui::blue())
|
.rounded_md()
|
||||||
.animate_in(AnimationDirection::FromTop, false),
|
.bg(gpui::blue())
|
||||||
)
|
.animate_in(AnimationDirection::FromTop, false),
|
||||||
.into_any_element(),
|
)
|
||||||
),
|
.into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"From Left",
|
single_example(
|
||||||
ContentGroup::new()
|
"From Left",
|
||||||
.relative()
|
ContentGroup::new()
|
||||||
.items_center()
|
.relative()
|
||||||
.justify_center()
|
.items_center()
|
||||||
.size(px(container_size))
|
.justify_center()
|
||||||
.child(
|
.size(px(container_size))
|
||||||
div()
|
.child(
|
||||||
.id("animate-in-from-left")
|
div()
|
||||||
.absolute()
|
.id("animate-in-from-left")
|
||||||
.size(px(element_size))
|
.absolute()
|
||||||
.left(px(left_offset))
|
.size(px(element_size))
|
||||||
.rounded_md()
|
.left(px(left_offset))
|
||||||
.bg(gpui::green())
|
.rounded_md()
|
||||||
.animate_in(AnimationDirection::FromLeft, false),
|
.bg(gpui::green())
|
||||||
)
|
.animate_in(AnimationDirection::FromLeft, false),
|
||||||
.into_any_element(),
|
)
|
||||||
),
|
.into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"From Right",
|
single_example(
|
||||||
ContentGroup::new()
|
"From Right",
|
||||||
.relative()
|
ContentGroup::new()
|
||||||
.items_center()
|
.relative()
|
||||||
.justify_center()
|
.items_center()
|
||||||
.size(px(container_size))
|
.justify_center()
|
||||||
.child(
|
.size(px(container_size))
|
||||||
div()
|
.child(
|
||||||
.id("animate-in-from-right")
|
div()
|
||||||
.absolute()
|
.id("animate-in-from-right")
|
||||||
.size(px(element_size))
|
.absolute()
|
||||||
.left(px(left_offset))
|
.size(px(element_size))
|
||||||
.rounded_md()
|
.left(px(left_offset))
|
||||||
.bg(gpui::yellow())
|
.rounded_md()
|
||||||
.animate_in(AnimationDirection::FromRight, false),
|
.bg(gpui::yellow())
|
||||||
)
|
.animate_in(AnimationDirection::FromRight, false),
|
||||||
.into_any_element(),
|
)
|
||||||
),
|
.into_any_element(),
|
||||||
],
|
),
|
||||||
)
|
],
|
||||||
.grow(),
|
)
|
||||||
example_group_with_title(
|
.grow(),
|
||||||
"Fade and Animate In",
|
example_group_with_title(
|
||||||
vec![
|
"Fade and Animate In",
|
||||||
single_example(
|
vec![
|
||||||
"From Bottom",
|
single_example(
|
||||||
ContentGroup::new()
|
"From Bottom",
|
||||||
.relative()
|
ContentGroup::new()
|
||||||
.items_center()
|
.relative()
|
||||||
.justify_center()
|
.items_center()
|
||||||
.size(px(container_size))
|
.justify_center()
|
||||||
.child(
|
.size(px(container_size))
|
||||||
div()
|
.child(
|
||||||
.id("fade-animate-in-from-bottom")
|
div()
|
||||||
.absolute()
|
.id("fade-animate-in-from-bottom")
|
||||||
.size(px(element_size))
|
.absolute()
|
||||||
.left(px(left_offset))
|
.size(px(element_size))
|
||||||
.rounded_md()
|
.left(px(left_offset))
|
||||||
.bg(gpui::red())
|
.rounded_md()
|
||||||
.animate_in(AnimationDirection::FromBottom, true),
|
.bg(gpui::red())
|
||||||
)
|
.animate_in(AnimationDirection::FromBottom, true),
|
||||||
.into_any_element(),
|
)
|
||||||
),
|
.into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"From Top",
|
single_example(
|
||||||
ContentGroup::new()
|
"From Top",
|
||||||
.relative()
|
ContentGroup::new()
|
||||||
.items_center()
|
.relative()
|
||||||
.justify_center()
|
.items_center()
|
||||||
.size(px(container_size))
|
.justify_center()
|
||||||
.child(
|
.size(px(container_size))
|
||||||
div()
|
.child(
|
||||||
.id("fade-animate-in-from-top")
|
div()
|
||||||
.absolute()
|
.id("fade-animate-in-from-top")
|
||||||
.size(px(element_size))
|
.absolute()
|
||||||
.left(px(left_offset))
|
.size(px(element_size))
|
||||||
.rounded_md()
|
.left(px(left_offset))
|
||||||
.bg(gpui::blue())
|
.rounded_md()
|
||||||
.animate_in(AnimationDirection::FromTop, true),
|
.bg(gpui::blue())
|
||||||
)
|
.animate_in(AnimationDirection::FromTop, true),
|
||||||
.into_any_element(),
|
)
|
||||||
),
|
.into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"From Left",
|
single_example(
|
||||||
ContentGroup::new()
|
"From Left",
|
||||||
.relative()
|
ContentGroup::new()
|
||||||
.items_center()
|
.relative()
|
||||||
.justify_center()
|
.items_center()
|
||||||
.size(px(container_size))
|
.justify_center()
|
||||||
.child(
|
.size(px(container_size))
|
||||||
div()
|
.child(
|
||||||
.id("fade-animate-in-from-left")
|
div()
|
||||||
.absolute()
|
.id("fade-animate-in-from-left")
|
||||||
.size(px(element_size))
|
.absolute()
|
||||||
.left(px(left_offset))
|
.size(px(element_size))
|
||||||
.rounded_md()
|
.left(px(left_offset))
|
||||||
.bg(gpui::green())
|
.rounded_md()
|
||||||
.animate_in(AnimationDirection::FromLeft, true),
|
.bg(gpui::green())
|
||||||
)
|
.animate_in(AnimationDirection::FromLeft, true),
|
||||||
.into_any_element(),
|
)
|
||||||
),
|
.into_any_element(),
|
||||||
single_example(
|
),
|
||||||
"From Right",
|
single_example(
|
||||||
ContentGroup::new()
|
"From Right",
|
||||||
.relative()
|
ContentGroup::new()
|
||||||
.items_center()
|
.relative()
|
||||||
.justify_center()
|
.items_center()
|
||||||
.size(px(container_size))
|
.justify_center()
|
||||||
.child(
|
.size(px(container_size))
|
||||||
div()
|
.child(
|
||||||
.id("fade-animate-in-from-right")
|
div()
|
||||||
.absolute()
|
.id("fade-animate-in-from-right")
|
||||||
.size(px(element_size))
|
.absolute()
|
||||||
.left(px(left_offset))
|
.size(px(element_size))
|
||||||
.rounded_md()
|
.left(px(left_offset))
|
||||||
.bg(gpui::yellow())
|
.rounded_md()
|
||||||
.animate_in(AnimationDirection::FromRight, true),
|
.bg(gpui::yellow())
|
||||||
)
|
.animate_in(AnimationDirection::FromRight, true),
|
||||||
.into_any_element(),
|
)
|
||||||
),
|
.into_any_element(),
|
||||||
],
|
),
|
||||||
)
|
],
|
||||||
.grow(),
|
)
|
||||||
])
|
.grow(),
|
||||||
.into_any_element()
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,21 @@
|
||||||
use gpui::{App, Hsla};
|
use crate::{Label, LabelCommon, component_prelude::*, v_flex};
|
||||||
|
use documented::{DocumentedFields, DocumentedVariants};
|
||||||
|
use gpui::{App, Hsla, IntoElement, ParentElement, Styled};
|
||||||
use theme::ActiveTheme;
|
use theme::ActiveTheme;
|
||||||
|
|
||||||
/// Sets a color that has a consistent meaning across all themes.
|
/// Sets a color that has a consistent meaning across all themes.
|
||||||
#[derive(Debug, Default, Eq, PartialEq, Copy, Clone)]
|
#[derive(
|
||||||
|
Debug,
|
||||||
|
Default,
|
||||||
|
Eq,
|
||||||
|
PartialEq,
|
||||||
|
Copy,
|
||||||
|
Clone,
|
||||||
|
RegisterComponent,
|
||||||
|
Documented,
|
||||||
|
DocumentedFields,
|
||||||
|
DocumentedVariants,
|
||||||
|
)]
|
||||||
pub enum Color {
|
pub enum Color {
|
||||||
#[default]
|
#[default]
|
||||||
/// The default text color. Might be known as "foreground" or "primary" in
|
/// The default text color. Might be known as "foreground" or "primary" in
|
||||||
|
@ -110,3 +123,122 @@ impl From<Hsla> for Color {
|
||||||
Color::Custom(color)
|
Color::Custom(color)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Component for Color {
|
||||||
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> Option<&'static str> {
|
||||||
|
Some(Color::DOCS)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(_window: &mut gpui::Window, _cx: &mut App) -> Option<gpui::AnyElement> {
|
||||||
|
Some(
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.children(vec![
|
||||||
|
example_group_with_title(
|
||||||
|
"Text Colors",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Default",
|
||||||
|
Label::new("Default text color")
|
||||||
|
.color(Color::Default)
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
.description(Color::Default.get_variant_docs()),
|
||||||
|
single_example(
|
||||||
|
"Muted",
|
||||||
|
Label::new("Muted text color")
|
||||||
|
.color(Color::Muted)
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
.description(Color::Muted.get_variant_docs()),
|
||||||
|
single_example(
|
||||||
|
"Accent",
|
||||||
|
Label::new("Accent text color")
|
||||||
|
.color(Color::Accent)
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
.description(Color::Accent.get_variant_docs()),
|
||||||
|
single_example(
|
||||||
|
"Disabled",
|
||||||
|
Label::new("Disabled text color")
|
||||||
|
.color(Color::Disabled)
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
.description(Color::Disabled.get_variant_docs()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Status Colors",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Success",
|
||||||
|
Label::new("Success status")
|
||||||
|
.color(Color::Success)
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
.description(Color::Success.get_variant_docs()),
|
||||||
|
single_example(
|
||||||
|
"Warning",
|
||||||
|
Label::new("Warning status")
|
||||||
|
.color(Color::Warning)
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
.description(Color::Warning.get_variant_docs()),
|
||||||
|
single_example(
|
||||||
|
"Error",
|
||||||
|
Label::new("Error status")
|
||||||
|
.color(Color::Error)
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
.description(Color::Error.get_variant_docs()),
|
||||||
|
single_example(
|
||||||
|
"Info",
|
||||||
|
Label::new("Info status")
|
||||||
|
.color(Color::Info)
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
.description(Color::Info.get_variant_docs()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Version Control Colors",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Created",
|
||||||
|
Label::new("Created item")
|
||||||
|
.color(Color::Created)
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
.description(Color::Created.get_variant_docs()),
|
||||||
|
single_example(
|
||||||
|
"Modified",
|
||||||
|
Label::new("Modified item")
|
||||||
|
.color(Color::Modified)
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
.description(Color::Modified.get_variant_docs()),
|
||||||
|
single_example(
|
||||||
|
"Deleted",
|
||||||
|
Label::new("Deleted item")
|
||||||
|
.color(Color::Deleted)
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
.description(Color::Deleted.get_variant_docs()),
|
||||||
|
single_example(
|
||||||
|
"Conflict",
|
||||||
|
Label::new("Conflict item")
|
||||||
|
.color(Color::Conflict)
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
.description(Color::Conflict.get_variant_docs()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -190,7 +190,7 @@ impl HeadlineSize {
|
||||||
|
|
||||||
/// A headline element, used to emphasize some text and
|
/// A headline element, used to emphasize some text and
|
||||||
/// create a visual hierarchy.
|
/// create a visual hierarchy.
|
||||||
#[derive(IntoElement, IntoComponent)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub struct Headline {
|
pub struct Headline {
|
||||||
size: HeadlineSize,
|
size: HeadlineSize,
|
||||||
text: SharedString,
|
text: SharedString,
|
||||||
|
@ -233,41 +233,50 @@ impl Headline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// View this component preview using `workspace: open component-preview`
|
impl Component for Headline {
|
||||||
impl ComponentPreview for Headline {
|
fn scope() -> ComponentScope {
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
ComponentScope::None
|
||||||
v_flex()
|
}
|
||||||
.gap_1()
|
|
||||||
.children(vec![
|
fn description() -> Option<&'static str> {
|
||||||
single_example(
|
Some("A headline element used to emphasize text and create visual hierarchy in the UI.")
|
||||||
"XLarge",
|
}
|
||||||
Headline::new("XLarge Headline")
|
|
||||||
.size(HeadlineSize::XLarge)
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
.into_any_element(),
|
Some(
|
||||||
),
|
v_flex()
|
||||||
single_example(
|
.gap_1()
|
||||||
"Large",
|
.children(vec![
|
||||||
Headline::new("Large Headline")
|
single_example(
|
||||||
.size(HeadlineSize::Large)
|
"XLarge",
|
||||||
.into_any_element(),
|
Headline::new("XLarge Headline")
|
||||||
),
|
.size(HeadlineSize::XLarge)
|
||||||
single_example(
|
.into_any_element(),
|
||||||
"Medium (Default)",
|
),
|
||||||
Headline::new("Medium Headline").into_any_element(),
|
single_example(
|
||||||
),
|
"Large",
|
||||||
single_example(
|
Headline::new("Large Headline")
|
||||||
"Small",
|
.size(HeadlineSize::Large)
|
||||||
Headline::new("Small Headline")
|
.into_any_element(),
|
||||||
.size(HeadlineSize::Small)
|
),
|
||||||
.into_any_element(),
|
single_example(
|
||||||
),
|
"Medium (Default)",
|
||||||
single_example(
|
Headline::new("Medium Headline").into_any_element(),
|
||||||
"XSmall",
|
),
|
||||||
Headline::new("XSmall Headline")
|
single_example(
|
||||||
.size(HeadlineSize::XSmall)
|
"Small",
|
||||||
.into_any_element(),
|
Headline::new("Small Headline")
|
||||||
),
|
.size(HeadlineSize::Small)
|
||||||
])
|
.into_any_element(),
|
||||||
.into_any_element()
|
),
|
||||||
|
single_example(
|
||||||
|
"XSmall",
|
||||||
|
Headline::new("XSmall Headline")
|
||||||
|
.size(HeadlineSize::XSmall)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
//! - [`ui_macros`] - proc_macros support for this crate
|
//! - [`ui_macros`] - proc_macros support for this crate
|
||||||
//! - `ui_input` - the single line input component
|
//! - `ui_input` - the single line input component
|
||||||
|
|
||||||
|
pub mod component_prelude;
|
||||||
mod components;
|
mod components;
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
mod styles;
|
mod styles;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! It can't be located in the `ui` crate because it depends on `editor`.
|
//! It can't be located in the `ui` crate because it depends on `editor`.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use component::{ComponentPreview, example_group, single_example};
|
use component::{example_group, single_example};
|
||||||
use editor::{Editor, EditorElement, EditorStyle};
|
use editor::{Editor, EditorElement, EditorStyle};
|
||||||
use gpui::{App, Entity, FocusHandle, Focusable, FontStyle, Hsla, TextStyle};
|
use gpui::{App, Entity, FocusHandle, Focusable, FontStyle, Hsla, TextStyle};
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
|
@ -21,8 +21,7 @@ pub struct SingleLineInputStyle {
|
||||||
/// A Text Field that can be used to create text fields like search inputs, form fields, etc.
|
/// A Text Field that can be used to create text fields like search inputs, form fields, etc.
|
||||||
///
|
///
|
||||||
/// It wraps a single line [`Editor`] and allows for common field properties like labels, placeholders, icons, etc.
|
/// It wraps a single line [`Editor`] and allows for common field properties like labels, placeholders, icons, etc.
|
||||||
#[derive(IntoComponent)]
|
#[derive(RegisterComponent)]
|
||||||
#[component(scope = "Input")]
|
|
||||||
pub struct SingleLineInput {
|
pub struct SingleLineInput {
|
||||||
/// An optional label for the text field.
|
/// An optional label for the text field.
|
||||||
///
|
///
|
||||||
|
@ -168,17 +167,23 @@ impl Render for SingleLineInput {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentPreview for SingleLineInput {
|
impl Component for SingleLineInput {
|
||||||
fn preview(window: &mut Window, cx: &mut App) -> AnyElement {
|
fn scope() -> ComponentScope {
|
||||||
|
ComponentScope::Input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview(window: &mut Window, cx: &mut App) -> Option<AnyElement> {
|
||||||
let input_1 =
|
let input_1 =
|
||||||
cx.new(|cx| SingleLineInput::new(window, cx, "placeholder").label("Some Label"));
|
cx.new(|cx| SingleLineInput::new(window, cx, "placeholder").label("Some Label"));
|
||||||
|
|
||||||
v_flex()
|
Some(
|
||||||
.gap_6()
|
v_flex()
|
||||||
.children(vec![example_group(vec![single_example(
|
.gap_6()
|
||||||
"Default",
|
.children(vec![example_group(vec![single_example(
|
||||||
div().child(input_1.clone()).into_any_element(),
|
"Default",
|
||||||
)])])
|
div().child(input_1.clone()).into_any_element(),
|
||||||
.into_any_element()
|
)])])
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
25
crates/ui_macros/src/derive_register_component.rs
Normal file
25
crates/ui_macros/src/derive_register_component.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
|
use syn::{DeriveInput, parse_macro_input};
|
||||||
|
|
||||||
|
pub fn derive_register_component(input: TokenStream) -> TokenStream {
|
||||||
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
|
let name = input.ident;
|
||||||
|
let reg_fn_name = syn::Ident::new(
|
||||||
|
&format!("__component_registry_internal_register_{}", name),
|
||||||
|
name.span(),
|
||||||
|
);
|
||||||
|
let expanded = quote! {
|
||||||
|
const _: () = {
|
||||||
|
struct AssertComponent<T: component::Component>(::std::marker::PhantomData<T>);
|
||||||
|
let _ = AssertComponent::<#name>(::std::marker::PhantomData);
|
||||||
|
};
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[linkme::distributed_slice(component::__ALL_COMPONENTS)]
|
||||||
|
fn #reg_fn_name() {
|
||||||
|
component::register_component::<#name>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expanded.into()
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
mod derive_component;
|
|
||||||
mod derive_path_str;
|
mod derive_path_str;
|
||||||
|
mod derive_register_component;
|
||||||
mod dynamic_spacing;
|
mod dynamic_spacing;
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
@ -60,26 +60,28 @@ pub fn derive_dynamic_spacing(input: TokenStream) -> TokenStream {
|
||||||
dynamic_spacing::derive_spacing(input)
|
dynamic_spacing::derive_spacing(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Derives the `Component` trait for a struct.
|
/// Registers components that implement the `Component` trait.
|
||||||
///
|
///
|
||||||
/// This macro generates implementations for the `Component` trait and associated
|
/// This proc macro is used to automatically register structs that implement
|
||||||
/// registration functions for the component system.
|
/// the `Component` trait with the [`component::ComponentRegistry`].
|
||||||
///
|
///
|
||||||
/// # Attributes
|
/// If the component trait is not implemented, it will generate a compile-time error.
|
||||||
///
|
|
||||||
/// - `#[component(scope = "...")]`: Required. Specifies the scope of the component.
|
|
||||||
/// - `#[component(description = "...")]`: Optional. Provides a description for the component.
|
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use ui_macros::Component;
|
/// use ui_macros::RegisterComponent;
|
||||||
///
|
///
|
||||||
/// #[derive(Component)]
|
/// #[derive(RegisterComponent)]
|
||||||
/// #[component(scope = "toggle", description = "A element that can be toggled on and off")]
|
/// struct MyComponent;
|
||||||
/// struct Checkbox;
|
///
|
||||||
|
/// impl Component for MyComponent {
|
||||||
|
/// // Component implementation
|
||||||
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[proc_macro_derive(IntoComponent, attributes(component))]
|
///
|
||||||
pub fn derive_component(input: TokenStream) -> TokenStream {
|
/// This example will add MyComponent to the ComponentRegistry.
|
||||||
derive_component::derive_into_component(input)
|
#[proc_macro_derive(RegisterComponent)]
|
||||||
|
pub fn derive_register_component(input: TokenStream) -> TokenStream {
|
||||||
|
derive_register_component::derive_register_component(input)
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,6 +267,7 @@ impl Render for WelcomePage {
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
v_container()
|
v_container()
|
||||||
|
.px_2()
|
||||||
.gap_2()
|
.gap_2()
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
|
|
|
@ -176,6 +176,7 @@ heck = { version = "0.4", features = ["unicode"] }
|
||||||
hmac = { version = "0.12", default-features = false, features = ["reset"] }
|
hmac = { version = "0.12", default-features = false, features = ["reset"] }
|
||||||
hyper = { version = "0.14", features = ["client", "http1", "http2", "runtime", "server", "stream"] }
|
hyper = { version = "0.14", features = ["client", "http1", "http2", "runtime", "server", "stream"] }
|
||||||
indexmap = { version = "2", features = ["serde"] }
|
indexmap = { version = "2", features = ["serde"] }
|
||||||
|
itertools-594e8ee84c453af0 = { package = "itertools", version = "0.13" }
|
||||||
lazy_static = { version = "1", default-features = false, features = ["spin_no_std"] }
|
lazy_static = { version = "1", default-features = false, features = ["spin_no_std"] }
|
||||||
libc = { version = "0.2", features = ["extra_traits"] }
|
libc = { version = "0.2", features = ["extra_traits"] }
|
||||||
libsqlite3-sys = { version = "0.30", features = ["bundled", "unlock_notify"] }
|
libsqlite3-sys = { version = "0.30", features = ["bundled", "unlock_notify"] }
|
||||||
|
@ -252,7 +253,7 @@ foldhash = { version = "0.1", default-features = false, features = ["std"] }
|
||||||
getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] }
|
getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] }
|
||||||
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
||||||
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
||||||
itertools = { version = "0.12" }
|
itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" }
|
||||||
naga = { version = "23", features = ["msl-out", "wgsl-in"] }
|
naga = { version = "23", features = ["msl-out", "wgsl-in"] }
|
||||||
nix = { version = "0.29", features = ["fs", "pthread", "signal"] }
|
nix = { version = "0.29", features = ["fs", "pthread", "signal"] }
|
||||||
object = { version = "0.36", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
|
object = { version = "0.36", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
|
||||||
|
@ -276,7 +277,7 @@ foldhash = { version = "0.1", default-features = false, features = ["std"] }
|
||||||
getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] }
|
getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] }
|
||||||
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
||||||
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
||||||
itertools = { version = "0.12" }
|
itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" }
|
||||||
naga = { version = "23", features = ["msl-out", "wgsl-in"] }
|
naga = { version = "23", features = ["msl-out", "wgsl-in"] }
|
||||||
nix = { version = "0.29", features = ["fs", "pthread", "signal"] }
|
nix = { version = "0.29", features = ["fs", "pthread", "signal"] }
|
||||||
object = { version = "0.36", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
|
object = { version = "0.36", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
|
||||||
|
@ -300,7 +301,7 @@ foldhash = { version = "0.1", default-features = false, features = ["std"] }
|
||||||
getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] }
|
getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] }
|
||||||
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
||||||
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
||||||
itertools = { version = "0.12" }
|
itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" }
|
||||||
naga = { version = "23", features = ["msl-out", "wgsl-in"] }
|
naga = { version = "23", features = ["msl-out", "wgsl-in"] }
|
||||||
nix = { version = "0.29", features = ["fs", "pthread", "signal"] }
|
nix = { version = "0.29", features = ["fs", "pthread", "signal"] }
|
||||||
object = { version = "0.36", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
|
object = { version = "0.36", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
|
||||||
|
@ -324,7 +325,7 @@ foldhash = { version = "0.1", default-features = false, features = ["std"] }
|
||||||
getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] }
|
getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] }
|
||||||
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
||||||
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
||||||
itertools = { version = "0.12" }
|
itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" }
|
||||||
naga = { version = "23", features = ["msl-out", "wgsl-in"] }
|
naga = { version = "23", features = ["msl-out", "wgsl-in"] }
|
||||||
nix = { version = "0.29", features = ["fs", "pthread", "signal"] }
|
nix = { version = "0.29", features = ["fs", "pthread", "signal"] }
|
||||||
object = { version = "0.36", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
|
object = { version = "0.36", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
|
||||||
|
@ -354,7 +355,7 @@ getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-f
|
||||||
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
||||||
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
||||||
inout = { version = "0.1", default-features = false, features = ["block-padding"] }
|
inout = { version = "0.1", default-features = false, features = ["block-padding"] }
|
||||||
itertools = { version = "0.12" }
|
itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" }
|
||||||
linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "system", "xdp"] }
|
linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "system", "xdp"] }
|
||||||
mio = { version = "1", features = ["net", "os-ext"] }
|
mio = { version = "1", features = ["net", "os-ext"] }
|
||||||
naga = { version = "23", features = ["spv-out", "wgsl-in"] }
|
naga = { version = "23", features = ["spv-out", "wgsl-in"] }
|
||||||
|
@ -394,7 +395,7 @@ getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-f
|
||||||
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
||||||
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
||||||
inout = { version = "0.1", default-features = false, features = ["block-padding"] }
|
inout = { version = "0.1", default-features = false, features = ["block-padding"] }
|
||||||
itertools = { version = "0.12" }
|
itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" }
|
||||||
linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "system", "xdp"] }
|
linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "system", "xdp"] }
|
||||||
mio = { version = "1", features = ["net", "os-ext"] }
|
mio = { version = "1", features = ["net", "os-ext"] }
|
||||||
naga = { version = "23", features = ["spv-out", "wgsl-in"] }
|
naga = { version = "23", features = ["spv-out", "wgsl-in"] }
|
||||||
|
@ -432,7 +433,7 @@ getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-f
|
||||||
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
||||||
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
||||||
inout = { version = "0.1", default-features = false, features = ["block-padding"] }
|
inout = { version = "0.1", default-features = false, features = ["block-padding"] }
|
||||||
itertools = { version = "0.12" }
|
itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" }
|
||||||
linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "system", "xdp"] }
|
linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "system", "xdp"] }
|
||||||
mio = { version = "1", features = ["net", "os-ext"] }
|
mio = { version = "1", features = ["net", "os-ext"] }
|
||||||
naga = { version = "23", features = ["spv-out", "wgsl-in"] }
|
naga = { version = "23", features = ["spv-out", "wgsl-in"] }
|
||||||
|
@ -472,7 +473,7 @@ getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-f
|
||||||
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
||||||
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
||||||
inout = { version = "0.1", default-features = false, features = ["block-padding"] }
|
inout = { version = "0.1", default-features = false, features = ["block-padding"] }
|
||||||
itertools = { version = "0.12" }
|
itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" }
|
||||||
linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "system", "xdp"] }
|
linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "system", "xdp"] }
|
||||||
mio = { version = "1", features = ["net", "os-ext"] }
|
mio = { version = "1", features = ["net", "os-ext"] }
|
||||||
naga = { version = "23", features = ["spv-out", "wgsl-in"] }
|
naga = { version = "23", features = ["spv-out", "wgsl-in"] }
|
||||||
|
@ -502,7 +503,7 @@ foldhash = { version = "0.1", default-features = false, features = ["std"] }
|
||||||
getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] }
|
getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] }
|
||||||
getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-features = false, features = ["js", "rdrand"] }
|
getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-features = false, features = ["js", "rdrand"] }
|
||||||
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
||||||
itertools = { version = "0.12" }
|
itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" }
|
||||||
naga = { version = "23", features = ["spv-out", "wgsl-in"] }
|
naga = { version = "23", features = ["spv-out", "wgsl-in"] }
|
||||||
ring = { version = "0.17", features = ["std"] }
|
ring = { version = "0.17", features = ["std"] }
|
||||||
rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38", default-features = false, features = ["event"] }
|
rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38", default-features = false, features = ["event"] }
|
||||||
|
@ -522,7 +523,7 @@ foldhash = { version = "0.1", default-features = false, features = ["std"] }
|
||||||
getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] }
|
getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] }
|
||||||
getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-features = false, features = ["js", "rdrand"] }
|
getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-features = false, features = ["js", "rdrand"] }
|
||||||
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
||||||
itertools = { version = "0.12" }
|
itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" }
|
||||||
naga = { version = "23", features = ["spv-out", "wgsl-in"] }
|
naga = { version = "23", features = ["spv-out", "wgsl-in"] }
|
||||||
proc-macro2 = { version = "1", default-features = false, features = ["span-locations"] }
|
proc-macro2 = { version = "1", default-features = false, features = ["span-locations"] }
|
||||||
ring = { version = "0.17", features = ["std"] }
|
ring = { version = "0.17", features = ["std"] }
|
||||||
|
@ -551,7 +552,7 @@ getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-f
|
||||||
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
||||||
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
||||||
inout = { version = "0.1", default-features = false, features = ["block-padding"] }
|
inout = { version = "0.1", default-features = false, features = ["block-padding"] }
|
||||||
itertools = { version = "0.12" }
|
itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" }
|
||||||
linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "system", "xdp"] }
|
linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "system", "xdp"] }
|
||||||
mio = { version = "1", features = ["net", "os-ext"] }
|
mio = { version = "1", features = ["net", "os-ext"] }
|
||||||
naga = { version = "23", features = ["spv-out", "wgsl-in"] }
|
naga = { version = "23", features = ["spv-out", "wgsl-in"] }
|
||||||
|
@ -591,7 +592,7 @@ getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-f
|
||||||
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] }
|
||||||
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
||||||
inout = { version = "0.1", default-features = false, features = ["block-padding"] }
|
inout = { version = "0.1", default-features = false, features = ["block-padding"] }
|
||||||
itertools = { version = "0.12" }
|
itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" }
|
||||||
linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "system", "xdp"] }
|
linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "system", "xdp"] }
|
||||||
mio = { version = "1", features = ["net", "os-ext"] }
|
mio = { version = "1", features = ["net", "os-ext"] }
|
||||||
naga = { version = "23", features = ["spv-out", "wgsl-in"] }
|
naga = { version = "23", features = ["spv-out", "wgsl-in"] }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue