mod button_story; mod checkbox_story; mod dropdown_story; mod input_story; mod picker_story; mod popover_story; mod switch_story; mod tooltip_stroy; use gpui::{ div, prelude::FluentBuilder as _, px, AnyElement, IntoElement, ParentElement, Render, RenderOnce, SharedString, StatefulInteractiveElement as _, Styled as _, View, ViewContext, VisualContext, WindowContext, }; use std::fmt::{self, Display, Formatter}; use ui::{ divider::Divider, label::Label, tab::{Tab, TabBar}, Icon, IconName, Selectable, }; use button_story::ButtonStory; use checkbox_story::CheckboxStory; use dropdown_story::DropdownStory; use input_story::InputStory; use picker_story::PickerStory; use popover_story::PopoverStory; use switch_story::SwitchStory; use tooltip_stroy::TooltipStory; pub fn story_case(name: &'static str, description: &'static str) -> StoryContainer { StoryContainer::new(name, description) } #[derive(IntoElement)] pub struct StoryContainer { name: SharedString, description: SharedString, children: Vec, } impl ParentElement for StoryContainer { fn extend(&mut self, elements: impl IntoIterator) { self.children.extend(elements) } } impl StoryContainer { pub fn new(name: impl Into, description: impl Into) -> Self { Self { name: name.into(), description: description.into(), children: Vec::new(), } } } impl RenderOnce for StoryContainer { fn render(self, _: &mut WindowContext) -> impl IntoElement { div() .size_full() .flex() .flex_col() .gap_6() .child( div() .flex() .flex_col() .gap_4() .child(Label::new(self.name).text_size(px(24.0))) .child(Label::new(self.description).text_size(px(16.0))), ) .child(Divider::horizontal()) .children(self.children) } } #[derive(Clone, Copy, PartialEq, Eq, Debug)] enum StoryType { Button, Input, Checkbox, Switch, Picker, Dropdown, Tooltip, Popover, } impl Display for StoryType { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Self::Button => write!(f, "Button"), Self::Input => write!(f, "Input"), Self::Checkbox => write!(f, "Checkbox"), Self::Switch => write!(f, "Switch"), Self::Picker => write!(f, "Picker"), Self::Dropdown => write!(f, "Dropdown"), Self::Tooltip => write!(f, "Tooltip"), Self::Popover => write!(f, "Popover"), } } } pub struct Stories { active: StoryType, button_story: View, input_story: View, checkbox_story: View, switch_story: View, picker_story: View, dropdown_story: View, tooltip_story: View, popover_story: View, } impl Stories { fn new(cx: &mut ViewContext) -> Self { Self { active: StoryType::Tooltip, button_story: cx.new_view(|_| ButtonStory {}), checkbox_story: cx.new_view(|cx| CheckboxStory::new(cx)), input_story: cx.new_view(|cx| InputStory::new(cx)), switch_story: cx.new_view(|cx| SwitchStory::new(cx)), tooltip_story: cx.new_view(|_| TooltipStory), picker_story: cx.new_view(PickerStory::new), dropdown_story: cx.new_view(DropdownStory::new), popover_story: cx.new_view(PopoverStory::new), } } pub fn view(cx: &mut WindowContext) -> View { cx.new_view(Self::new) } fn set_active(&mut self, ty: StoryType, cx: &mut ViewContext) { self.active = ty; cx.notify(); } fn tabs(&self, cx: &mut ViewContext) -> impl IntoElement { div() .flex() .items_center() .gap_4() .w_full() .child(TabBar::new("story-tabs").children(vec![ self.tab("story-button", StoryType::Button, Some(IconName::Close), cx), self.tab("story-input", StoryType::Input, None, cx), self.tab( "story-checkbox", StoryType::Checkbox, Some(IconName::Check), cx, ), self.tab("story-switch", StoryType::Switch, None, cx), self.tab("story-picker", StoryType::Picker, None, cx), self.tab("story-dropdown", StoryType::Dropdown, None, cx), self.tab("story-tooltip", StoryType::Tooltip, None, cx), self.tab("story-popover", StoryType::Popover, None, cx), ])) } fn tab( &self, id: &str, ty: StoryType, icon: Option>, cx: &mut ViewContext, ) -> impl IntoElement { let name = format!("{}", ty); let is_active = ty == self.active; let tab = Tab::new(SharedString::from(id.to_string()), name) .selected(is_active) .on_click(cx.listener(move |this, _, cx| { this.set_active(ty, cx); })); if let Some(icon) = icon { tab.prefix(icon.into()) } else { tab } } } impl Render for Stories { fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { div() .w_full() .flex() .flex_col() .gap_4() .child(self.tabs(cx)) .map(|this| match self.active { StoryType::Button => this.child(self.button_story.clone()), StoryType::Input => this.child(self.input_story.clone()), StoryType::Checkbox => this.child(self.checkbox_story.clone()), StoryType::Switch => this.child(self.switch_story.clone()), StoryType::Picker => this.child(self.picker_story.clone()), StoryType::Dropdown => this.child(self.dropdown_story.clone()), StoryType::Tooltip => this.child(self.tooltip_story.clone()), StoryType::Popover => this.child(self.popover_story.clone()), }) } }