diff --git a/crates/app/src/story_workspace.rs b/crates/app/src/story_workspace.rs index 3001161b..5ca92c76 100644 --- a/crates/app/src/story_workspace.rs +++ b/crates/app/src/story_workspace.rs @@ -2,7 +2,7 @@ use gpui::*; use prelude::FluentBuilder as _; use story::{ ButtonStory, CheckboxStory, DropdownStory, ImageStory, InputStory, ListStory, PickerStory, - PopoverStory, StoryContainer, SwitchStory, TableStory, TooltipStory, + PopoverStory, ProgressStory, StoryContainer, SwitchStory, TableStory, TooltipStory, }; use workspace::{dock::DockPosition, TitleBar, Workspace}; @@ -137,6 +137,15 @@ impl StoryWorkspace { ) .detach(); + StoryContainer::add_pane( + "Progress", + "Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.", + ProgressStory::view(cx).into(), + workspace.clone(), + cx, + ) + .detach(); + Self { workspace } } diff --git a/crates/story/src/lib.rs b/crates/story/src/lib.rs index 1bbf040b..1a283625 100644 --- a/crates/story/src/lib.rs +++ b/crates/story/src/lib.rs @@ -6,6 +6,7 @@ mod input_story; mod list_story; mod picker_story; mod popover_story; +mod progress_story; mod switch_story; mod table_story; mod tooltip_story; @@ -18,15 +19,15 @@ pub use input_story::InputStory; pub use list_story::ListStory; pub use picker_story::PickerStory; pub use popover_story::PopoverStory; +pub use progress_story::ProgressStory; pub use switch_story::SwitchStory; pub use table_story::TableStory; pub use tooltip_story::TooltipStory; use gpui::{ div, prelude::FluentBuilder as _, px, AnyElement, AnyView, AppContext, Div, EventEmitter, - FocusableView, InteractiveElement, IntoElement, ParentElement, Pixels, Render, - SharedString, StatefulInteractiveElement, Styled as _, Task, View, ViewContext, VisualContext, - WindowContext, + FocusableView, InteractiveElement, IntoElement, ParentElement, Pixels, Render, SharedString, + StatefulInteractiveElement, Styled as _, Task, View, ViewContext, VisualContext, WindowContext, }; use workspace::{ dock::{DockPosition, Panel, PanelEvent}, diff --git a/crates/story/src/popover_story.rs b/crates/story/src/popover_story.rs index 39e34561..ef885df5 100644 --- a/crates/story/src/popover_story.rs +++ b/crates/story/src/popover_story.rs @@ -180,7 +180,7 @@ impl Render for PopoverStory { .trigger(Button::new("popup-menu-1", cx).icon(IconName::Info)) .content(move |cx| { let focus_handle = focus_handle.clone(); - PopupMenu::build(cx, |mut this, cx| { + PopupMenu::build(cx, |mut this, _cx| { this.content(focus_handle) .menu("Copy", Box::new(Copy)) .menu("Cut", Box::new(Cut)) diff --git a/crates/story/src/progress_story.rs b/crates/story/src/progress_story.rs new file mode 100644 index 00000000..95792f48 --- /dev/null +++ b/crates/story/src/progress_story.rs @@ -0,0 +1,78 @@ +use gpui::{ + div, IntoElement, ParentElement, Render, Styled, View, ViewContext, VisualContext, + WindowContext, +}; +use ui::{button::Button, h_flex, progress::Progress, v_flex, Clickable, IconName}; + +pub struct ProgressStory { + value: f32, +} + +impl ProgressStory { + pub fn view(cx: &mut WindowContext) -> View { + cx.new_view(|_| Self { value: 50. }) + } + + pub fn set_value(&mut self, value: f32) { + self.value = value; + } +} + +impl Render for ProgressStory { + fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + v_flex() + .items_center() + .gap_y_3() + .child( + h_flex() + .gap_x_2() + .child( + Button::new("button-1", cx) + .label("0%") + .on_click(cx.listener(|this, _, _| { + this.set_value(0.); + })), + ) + .child( + Button::new("button-2", cx) + .label("25%") + .on_click(cx.listener(|this, _, _| { + this.set_value(25.); + })), + ) + .child( + Button::new("button-3", cx) + .label("75%") + .on_click(cx.listener(|this, _, _| { + this.set_value(75.); + })), + ) + .child( + Button::new("button-4", cx) + .label("100%") + .on_click(cx.listener(|this, _, _| { + this.set_value(100.); + })), + ), + ) + .child(div().w_1_2().child(Progress::new().value(self.value))) + .child( + h_flex() + .gap_x_2() + .child( + Button::new("button-5", cx) + .icon(IconName::Minus) + .on_click(cx.listener(|this, _, _| { + this.set_value(this.value - 1.); + })), + ) + .child( + Button::new("button-6", cx) + .icon(IconName::Plus) + .on_click(cx.listener(|this, _, _| { + this.set_value(this.value + 1.); + })), + ), + ) + } +} diff --git a/crates/ui/src/icon.rs b/crates/ui/src/icon.rs index 11044b69..06239b65 100644 --- a/crates/ui/src/icon.rs +++ b/crates/ui/src/icon.rs @@ -20,7 +20,7 @@ pub enum IconName { EllipsisVertical, Search, Delete, - CicleX, + CircleX, } impl IconName { @@ -40,7 +40,7 @@ impl IconName { IconName::EllipsisVertical => "icons/ellipsis-vertical.svg", IconName::Search => "icons/search.svg", IconName::Delete => "icons/delete.svg", - IconName::CicleX => "icons/circle-x.svg", + IconName::CircleX => "icons/circle-x.svg", } .into() } diff --git a/crates/ui/src/lib.rs b/crates/ui/src/lib.rs index c512e17e..4916e69b 100644 --- a/crates/ui/src/lib.rs +++ b/crates/ui/src/lib.rs @@ -13,19 +13,19 @@ mod svg_img; pub mod button; pub mod checkbox; -pub mod label; -pub mod prelude; -pub mod theme; -pub use styled_ext::StyledExt; pub mod divider; pub mod dropdown; pub mod input; +pub mod label; pub mod list; pub mod popover; pub mod popup_menu; +pub mod prelude; +pub mod progress; pub mod switch; pub mod tab; pub mod table; +pub mod theme; pub mod tooltip; pub use clickable::Clickable; @@ -33,6 +33,7 @@ pub use disableable::Disableable; pub use event::InterativeElementExt; pub use focusable::FocusableCycle; pub use selectable::{Selectable, Selection}; +pub use styled_ext::StyledExt; pub use colors::*; pub use icon::*; diff --git a/crates/ui/src/popup_menu.rs b/crates/ui/src/popup_menu.rs index c9a72832..98425230 100644 --- a/crates/ui/src/popup_menu.rs +++ b/crates/ui/src/popup_menu.rs @@ -7,7 +7,7 @@ use gpui::{ WindowContext, }; -use crate::{h_flex, list::ListItem, theme::ActiveTheme, v_flex, Icon, StyledExt}; +use crate::{h_flex, list::ListItem, theme::ActiveTheme, v_flex, Icon}; actions!(menu, [Confirm, Dismiss, SelectNext, SelectPrev]); diff --git a/crates/ui/src/progress.rs b/crates/ui/src/progress.rs new file mode 100644 index 00000000..c7516552 --- /dev/null +++ b/crates/ui/src/progress.rs @@ -0,0 +1,63 @@ +use gpui::{ + div, prelude::FluentBuilder, px, relative, IntoElement, ParentElement, RenderOnce, Styled, + WindowContext, +}; + +use crate::{ + h_flex, + theme::{ActiveTheme, Colorize}, +}; + +#[derive(IntoElement)] +pub struct Progress { + value: f32, + height: f32, +} + +impl Progress { + pub fn new() -> Self { + Progress { + value: Default::default(), + height: 8., + } + } + + pub fn value(mut self, value: f32) -> Self { + self.value = value; + self + } +} + +impl RenderOnce for Progress { + fn render(self, cx: &mut WindowContext) -> impl IntoElement { + let rounded = px(self.height / 2.); + let relative_w = relative(match self.value { + v if v < 0. => 0., + v if v > 100. => 1., + v => v / 100., + }); + + h_flex() + .h(px(self.height)) + .child( + div() + .map(|this| match self.value { + v if v >= 100. => this.rounded(rounded), + _ => this.rounded_l(rounded), + }) + .h_full() + .w(relative_w) + .bg(cx.theme().primary), + ) + .child( + div() + .map(|this| match self.value { + v if v <= 0. => this.rounded(rounded), + _ => this.rounded_r(rounded), + }) + .h_full() + .flex_1() + .bg(cx.theme().primary.opacity(0.2)), + ) + } +} diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 4aaa86c7..3fce6618 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -13,8 +13,8 @@ use gpui::{ actions, div, impl_actions, prelude::FluentBuilder as _, px, AppContext, DefiniteLength, DragMoveEvent, Element as _, EntityId, EventEmitter, FocusHandle, FocusOutEvent, FocusableView, InteractiveElement as _, IntoElement, KeyContext, ParentElement, Pixels, Point, Render, - RenderOnce as _, ScrollHandle, StatefulInteractiveElement, Styled, Subscription, Task, View, - ViewContext, VisualContext as _, WeakFocusHandle, WeakView, WindowContext, + ScrollHandle, StatefulInteractiveElement, Styled, Subscription, Task, View, ViewContext, + VisualContext as _, WeakFocusHandle, WeakView, WindowContext, }; use serde::Deserialize;