Update dock layout
This commit is contained in:
parent
19930e46db
commit
f78d50b5e9
13 changed files with 279 additions and 159 deletions
|
|
@ -4,7 +4,7 @@ use story::{
|
||||||
ButtonStory, CheckboxStory, DropdownStory, ImageStory, InputStory, ListStory, PickerStory,
|
ButtonStory, CheckboxStory, DropdownStory, ImageStory, InputStory, ListStory, PickerStory,
|
||||||
PopoverStory, StoryContainer, SwitchStory, TooltipStory,
|
PopoverStory, StoryContainer, SwitchStory, TooltipStory,
|
||||||
};
|
};
|
||||||
use workspace::{TitleBar, Workspace};
|
use workspace::{dock::DockPosition, TitleBar, Workspace};
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use ui::{
|
use ui::{
|
||||||
|
|
@ -40,7 +40,7 @@ impl StoryWorkspace {
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
StoryContainer::open(
|
StoryContainer::add_pane(
|
||||||
"Buttons",
|
"Buttons",
|
||||||
"Displays a button or a component that looks like a button.",
|
"Displays a button or a component that looks like a button.",
|
||||||
ButtonStory::view(cx).into(),
|
ButtonStory::view(cx).into(),
|
||||||
|
|
@ -49,25 +49,23 @@ impl StoryWorkspace {
|
||||||
)
|
)
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
StoryContainer::open(
|
StoryContainer::add_panel(
|
||||||
"Inputs",
|
|
||||||
"Displays a text input field.",
|
|
||||||
InputStory::view(cx).into(),
|
InputStory::view(cx).into(),
|
||||||
workspace.clone(),
|
workspace.clone(),
|
||||||
|
DockPosition::Right,
|
||||||
|
px(500.0),
|
||||||
cx,
|
cx,
|
||||||
)
|
);
|
||||||
.detach();
|
|
||||||
|
|
||||||
StoryContainer::open(
|
StoryContainer::add_panel(
|
||||||
"Checkbox",
|
|
||||||
"A control that allows the user to toggle between checked and not checked.",
|
|
||||||
CheckboxStory::view(cx).into(),
|
CheckboxStory::view(cx).into(),
|
||||||
workspace.clone(),
|
workspace.clone(),
|
||||||
|
DockPosition::Bottom,
|
||||||
|
px(300.),
|
||||||
cx,
|
cx,
|
||||||
)
|
);
|
||||||
.detach();
|
|
||||||
|
|
||||||
StoryContainer::open(
|
StoryContainer::add_pane(
|
||||||
"Switch",
|
"Switch",
|
||||||
"A control that allows the user to toggle between two states.",
|
"A control that allows the user to toggle between two states.",
|
||||||
SwitchStory::view(cx).into(),
|
SwitchStory::view(cx).into(),
|
||||||
|
|
@ -76,7 +74,7 @@ impl StoryWorkspace {
|
||||||
)
|
)
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
StoryContainer::open(
|
StoryContainer::add_pane(
|
||||||
"Dropdowns",
|
"Dropdowns",
|
||||||
"Displays a list of options for the user to pick from—triggered by a button.",
|
"Displays a list of options for the user to pick from—triggered by a button.",
|
||||||
DropdownStory::new(cx).into(),
|
DropdownStory::new(cx).into(),
|
||||||
|
|
@ -85,7 +83,7 @@ impl StoryWorkspace {
|
||||||
)
|
)
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
StoryContainer::open(
|
StoryContainer::add_pane(
|
||||||
"Picker",
|
"Picker",
|
||||||
"Picker is a component that allows the user to select an item from a list of options.",
|
"Picker is a component that allows the user to select an item from a list of options.",
|
||||||
PickerStory::view(cx).into(),
|
PickerStory::view(cx).into(),
|
||||||
|
|
@ -94,7 +92,7 @@ impl StoryWorkspace {
|
||||||
)
|
)
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
StoryContainer::open(
|
StoryContainer::add_pane(
|
||||||
"Popover",
|
"Popover",
|
||||||
"Displays rich content in a portal, triggered by a button.",
|
"Displays rich content in a portal, triggered by a button.",
|
||||||
PopoverStory::view(cx).into(),
|
PopoverStory::view(cx).into(),
|
||||||
|
|
@ -103,24 +101,24 @@ impl StoryWorkspace {
|
||||||
)
|
)
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
StoryContainer::open(
|
StoryContainer::add_pane(
|
||||||
"Tooltip",
|
"Tooltip",
|
||||||
"A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.",
|
"Displays a short message when users hover over an element.",
|
||||||
TooltipStory::view(cx).into(),
|
TooltipStory::view(cx).into(),
|
||||||
workspace.clone(),
|
workspace.clone(),
|
||||||
cx,
|
cx,
|
||||||
).detach();
|
|
||||||
|
|
||||||
StoryContainer::open(
|
|
||||||
"List",
|
|
||||||
"A complex list example, includes use Picker, Scrollbar, and more.",
|
|
||||||
ListStory::view(cx).into(),
|
|
||||||
workspace.clone(),
|
|
||||||
cx,
|
|
||||||
)
|
)
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
StoryContainer::open(
|
StoryContainer::add_panel(
|
||||||
|
ListStory::view(cx).into(),
|
||||||
|
workspace.clone(),
|
||||||
|
DockPosition::Left,
|
||||||
|
px(360.),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
|
||||||
|
StoryContainer::add_pane(
|
||||||
"Image",
|
"Image",
|
||||||
"Render SVG image and Chart",
|
"Render SVG image and Chart",
|
||||||
ImageStory::view(cx).into(),
|
ImageStory::view(cx).into(),
|
||||||
|
|
@ -136,7 +134,7 @@ impl StoryWorkspace {
|
||||||
app_state: Arc<AppState>,
|
app_state: Arc<AppState>,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Task<anyhow::Result<WindowHandle<Self>>> {
|
) -> Task<anyhow::Result<WindowHandle<Self>>> {
|
||||||
let window_bounds = Bounds::centered(None, size(px(1200.0), px(900.0)), cx);
|
let window_bounds = Bounds::centered(None, size(px(1600.0), px(1200.0)), cx);
|
||||||
|
|
||||||
cx.spawn(|mut cx| async move {
|
cx.spawn(|mut cx| async move {
|
||||||
let options = WindowOptions {
|
let options = WindowOptions {
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ impl CheckboxStory {
|
||||||
impl Render for CheckboxStory {
|
impl Render for CheckboxStory {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
v_flex()
|
v_flex()
|
||||||
|
.p_4()
|
||||||
.gap_6()
|
.gap_6()
|
||||||
.child(
|
.child(
|
||||||
v_flex().items_start().justify_start().gap_6().child(
|
v_flex().items_start().justify_start().gap_6().child(
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ impl Render for InputStory {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
v_flex()
|
v_flex()
|
||||||
.size_full()
|
.size_full()
|
||||||
|
.p_4()
|
||||||
.justify_start()
|
.justify_start()
|
||||||
.gap_3()
|
.gap_3()
|
||||||
.child(
|
.child(
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,10 @@ pub use switch_story::SwitchStory;
|
||||||
pub use tooltip_story::TooltipStory;
|
pub use tooltip_story::TooltipStory;
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::FluentBuilder as _, px, AnyElement, AnyView, AppContext, Div, EventEmitter,
|
div, prelude::FluentBuilder as _, px, AnyElement, AnyView, AppContext, Div, Element,
|
||||||
FocusableView, IntoElement, ParentElement, Render, SharedString, Styled as _, Task, View,
|
EventEmitter, FocusableView, InteractiveElement, IntoElement, ParentElement, Pixels, Render,
|
||||||
ViewContext, VisualContext, WindowContext,
|
ScrollHandle, SharedString, StatefulInteractiveElement, Styled as _, Task, View, ViewContext,
|
||||||
|
VisualContext, WindowContext,
|
||||||
};
|
};
|
||||||
use workspace::{
|
use workspace::{
|
||||||
dock::{DockPosition, Panel, PanelEvent},
|
dock::{DockPosition, Panel, PanelEvent},
|
||||||
|
|
@ -32,7 +33,7 @@ use workspace::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use ui::{divider::Divider, h_flex, label::Label, v_flex};
|
use ui::{divider::Divider, h_flex, label::Label, v_flex, StyledExt};
|
||||||
|
|
||||||
pub fn story_case(
|
pub fn story_case(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
|
|
@ -61,6 +62,7 @@ pub fn section(title: impl Into<SharedString>, cx: &WindowContext) -> Div {
|
||||||
|
|
||||||
pub struct StoryContainer {
|
pub struct StoryContainer {
|
||||||
focus_handle: gpui::FocusHandle,
|
focus_handle: gpui::FocusHandle,
|
||||||
|
scroll_handle: gpui::ScrollHandle,
|
||||||
name: SharedString,
|
name: SharedString,
|
||||||
description: SharedString,
|
description: SharedString,
|
||||||
position: DockPosition,
|
position: DockPosition,
|
||||||
|
|
@ -76,48 +78,6 @@ impl FocusableView for StoryContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventEmitter<PanelEvent> for StoryContainer {}
|
|
||||||
|
|
||||||
impl Panel for StoryContainer {
|
|
||||||
fn persistent_name() -> &'static str {
|
|
||||||
"story-container"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn position(&self, _: &WindowContext) -> workspace::dock::DockPosition {
|
|
||||||
self.position
|
|
||||||
}
|
|
||||||
|
|
||||||
fn can_position(&self, _: workspace::dock::DockPosition, _: &WindowContext) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_position(&mut self, position: workspace::dock::DockPosition, _: &mut WindowContext) {
|
|
||||||
self.position = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size(&self, _: &WindowContext) -> gpui::Pixels {
|
|
||||||
match self.position {
|
|
||||||
DockPosition::Left | DockPosition::Right => self.width.unwrap_or(px(360.)),
|
|
||||||
DockPosition::Bottom => self.height.unwrap_or(px(360.)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_size(&mut self, size: Option<gpui::Pixels>, _: &mut WindowContext) {
|
|
||||||
match self.position {
|
|
||||||
DockPosition::Left | DockPosition::Right => self.width = size,
|
|
||||||
DockPosition::Bottom => self.height = size,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_active(&mut self, active: bool, _: &mut WindowContext) {
|
|
||||||
self.active = active;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn starts_open(&self, _cx: &WindowContext) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ContainerEvent {
|
pub enum ContainerEvent {
|
||||||
Close,
|
Close,
|
||||||
|
|
@ -172,6 +132,7 @@ impl StoryContainer {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
focus_handle,
|
focus_handle,
|
||||||
|
scroll_handle: ScrollHandle::new(),
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
description: description.into(),
|
description: description.into(),
|
||||||
width: None,
|
width: None,
|
||||||
|
|
@ -182,7 +143,7 @@ impl StoryContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open(
|
pub fn add_pane(
|
||||||
name: impl Into<SharedString>,
|
name: impl Into<SharedString>,
|
||||||
description: impl Into<SharedString>,
|
description: impl Into<SharedString>,
|
||||||
story: AnyView,
|
story: AnyView,
|
||||||
|
|
@ -203,6 +164,19 @@ impl StoryContainer {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_panel(
|
||||||
|
story: AnyView,
|
||||||
|
workspace: View<Workspace>,
|
||||||
|
position: DockPosition,
|
||||||
|
size: gpui::Pixels,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) {
|
||||||
|
workspace.update(cx, |workspace, cx| {
|
||||||
|
let panel = cx.new_view(|cx| MyPanel::new(story, position, size, cx));
|
||||||
|
workspace.add_panel(panel, cx)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn width(mut self, width: gpui::Pixels) -> Self {
|
pub fn width(mut self, width: gpui::Pixels) -> Self {
|
||||||
self.width = Some(width);
|
self.width = Some(width);
|
||||||
self
|
self
|
||||||
|
|
@ -226,21 +200,112 @@ impl StoryContainer {
|
||||||
|
|
||||||
impl Render for StoryContainer {
|
impl Render for StoryContainer {
|
||||||
fn render(&mut self, _: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, _: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
v_flex()
|
div()
|
||||||
|
.id("story-container")
|
||||||
|
.overflow_y_scroll()
|
||||||
|
.track_scroll(&self.scroll_handle)
|
||||||
.size_full()
|
.size_full()
|
||||||
.gap_6()
|
|
||||||
.p_2()
|
|
||||||
.child(
|
.child(
|
||||||
div()
|
v_flex()
|
||||||
.flex()
|
.size_full()
|
||||||
.flex_col()
|
.gap_6()
|
||||||
.gap_4()
|
.p_4()
|
||||||
.child(Label::new(self.name.clone()).text_size(px(24.0)))
|
.child(
|
||||||
.child(Label::new(self.description.clone()).text_size(px(16.0))),
|
div()
|
||||||
|
.flex()
|
||||||
|
.flex_col()
|
||||||
|
.gap_4()
|
||||||
|
.child(Label::new(self.name.clone()).text_size(px(24.0)))
|
||||||
|
.child(Label::new(self.description.clone()).text_size(px(16.0))),
|
||||||
|
)
|
||||||
|
.child(Divider::horizontal())
|
||||||
|
.when_some(self.story.clone(), |this, story| {
|
||||||
|
this.child(v_flex().size_full().child(story))
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
.child(Divider::horizontal())
|
}
|
||||||
.when_some(self.story.clone(), |this, story| {
|
}
|
||||||
this.child(v_flex().size_full().child(story))
|
|
||||||
})
|
struct MyPanel {
|
||||||
|
focus_handle: gpui::FocusHandle,
|
||||||
|
view: AnyView,
|
||||||
|
_position: DockPosition,
|
||||||
|
width: Option<Pixels>,
|
||||||
|
height: Option<Pixels>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyPanel {
|
||||||
|
fn new(view: AnyView, position: DockPosition, size: Pixels, cx: &mut WindowContext) -> Self {
|
||||||
|
let mut this = Self {
|
||||||
|
focus_handle: cx.focus_handle(),
|
||||||
|
view,
|
||||||
|
_position: position,
|
||||||
|
width: None,
|
||||||
|
height: None,
|
||||||
|
};
|
||||||
|
this.update_size(size);
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_size(&mut self, size: Pixels) {
|
||||||
|
match self._position {
|
||||||
|
DockPosition::Bottom => self.height = Some(size),
|
||||||
|
DockPosition::Left | DockPosition::Right => self.width = Some(size),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Panel for MyPanel {
|
||||||
|
fn persistent_name() -> &'static str {
|
||||||
|
"my-panel"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_position(&self, position: DockPosition) -> bool {
|
||||||
|
match self._position {
|
||||||
|
DockPosition::Bottom => matches!(position, DockPosition::Bottom),
|
||||||
|
DockPosition::Left | DockPosition::Right => {
|
||||||
|
matches!(position, DockPosition::Left | DockPosition::Right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn position(&self, _cx: &WindowContext) -> DockPosition {
|
||||||
|
self._position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext<Self>) {
|
||||||
|
self._position = position;
|
||||||
|
cx.notify()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self, _cx: &WindowContext) -> gpui::Pixels {
|
||||||
|
match self._position {
|
||||||
|
DockPosition::Bottom => self.height.unwrap_or(px(100.)),
|
||||||
|
DockPosition::Left | DockPosition::Right => self.width.unwrap_or(px(100.)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_size(&mut self, size: Option<gpui::Pixels>, cx: &mut ViewContext<Self>) {
|
||||||
|
dbg!("================ set_size", size);
|
||||||
|
if let Some(size) = size {
|
||||||
|
self.update_size(size)
|
||||||
|
}
|
||||||
|
cx.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventEmitter<PanelEvent> for MyPanel {}
|
||||||
|
impl FocusableView for MyPanel {
|
||||||
|
fn focus_handle(&self, _: &AppContext) -> gpui::FocusHandle {
|
||||||
|
self.focus_handle.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Render for MyPanel {
|
||||||
|
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
|
div()
|
||||||
|
.id("my-panel")
|
||||||
|
.track_focus(&self.focus_handle)
|
||||||
|
.size_full()
|
||||||
|
.child(self.view.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ use core::time;
|
||||||
|
|
||||||
use fake::Fake;
|
use fake::Fake;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, div, prelude::FluentBuilder as _, px, ElementId, InteractiveElement, IntoElement,
|
actions, div, prelude::FluentBuilder as _, px, ElementId, FocusHandle, FocusableView,
|
||||||
ParentElement, Render, RenderOnce, Styled, Timer, View, ViewContext, VisualContext,
|
InteractiveElement, IntoElement, ParentElement, Render, RenderOnce, Styled, Timer, View,
|
||||||
WindowContext,
|
ViewContext, VisualContext, WindowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
use ui::{
|
use ui::{
|
||||||
|
|
@ -175,22 +175,11 @@ impl CompanyListDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ListStory {
|
pub struct ListStory {
|
||||||
|
focus_handle: FocusHandle,
|
||||||
company_list: View<Picker<CompanyListDelegate>>,
|
company_list: View<Picker<CompanyListDelegate>>,
|
||||||
selected_company: Option<Company>,
|
selected_company: Option<Company>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_company() -> Company {
|
|
||||||
let last_done = (0.0..999.0).fake::<f64>();
|
|
||||||
let prev_close = last_done * (-0.1..0.1).fake::<f64>();
|
|
||||||
Company {
|
|
||||||
name: fake::faker::company::en::CompanyName().fake(),
|
|
||||||
industry: fake::faker::company::en::Industry().fake(),
|
|
||||||
description: fake::faker::lorem::en::Paragraph(3..5).fake(),
|
|
||||||
last_done,
|
|
||||||
prev_close,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ListStory {
|
impl ListStory {
|
||||||
pub fn view(cx: &mut WindowContext) -> View<Self> {
|
pub fn view(cx: &mut WindowContext) -> View<Self> {
|
||||||
cx.new_view(|cx| Self::new(cx))
|
cx.new_view(|cx| Self::new(cx))
|
||||||
|
|
@ -235,6 +224,7 @@ impl ListStory {
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
focus_handle: cx.focus_handle(),
|
||||||
company_list,
|
company_list,
|
||||||
selected_company: None,
|
selected_company: None,
|
||||||
}
|
}
|
||||||
|
|
@ -248,48 +238,68 @@ impl ListStory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn random_company() -> Company {
|
||||||
|
let last_done = (0.0..999.0).fake::<f64>();
|
||||||
|
let prev_close = last_done * (-0.1..0.1).fake::<f64>();
|
||||||
|
Company {
|
||||||
|
name: fake::faker::company::en::CompanyName().fake(),
|
||||||
|
industry: fake::faker::company::en::Industry().fake(),
|
||||||
|
description: fake::faker::lorem::en::Paragraph(3..5).fake(),
|
||||||
|
last_done,
|
||||||
|
prev_close,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FocusableView for ListStory {
|
||||||
|
fn focus_handle(&self, cx: &gpui::AppContext) -> FocusHandle {
|
||||||
|
self.focus_handle.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Render for ListStory {
|
impl Render for ListStory {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
h_flex()
|
h_flex()
|
||||||
.size_full()
|
.track_focus(&self.focus_handle)
|
||||||
.on_action(cx.listener(Self::selected_company))
|
.on_action(cx.listener(Self::selected_company))
|
||||||
|
.size_full()
|
||||||
.gap_4()
|
.gap_4()
|
||||||
.mb_4()
|
.mb_4()
|
||||||
.child(
|
.child(
|
||||||
v_flex()
|
v_flex()
|
||||||
.h_full()
|
.h_full()
|
||||||
|
.w_full()
|
||||||
.border_1()
|
.border_1()
|
||||||
.border_color(cx.theme().border)
|
.border_color(cx.theme().border)
|
||||||
.rounded_md()
|
.rounded_md()
|
||||||
.w(px(400.))
|
|
||||||
.occlude()
|
.occlude()
|
||||||
.child(self.company_list.clone()),
|
.child(self.company_list.clone()),
|
||||||
)
|
)
|
||||||
.child(
|
// .child(
|
||||||
div()
|
// div()
|
||||||
.flex_1()
|
// .invisible()
|
||||||
.size_full()
|
// .flex_1()
|
||||||
.border_1()
|
// .size_full()
|
||||||
.border_color(cx.theme().border)
|
// .border_1()
|
||||||
.py_1()
|
// .border_color(cx.theme().border)
|
||||||
.px_4()
|
// .py_1()
|
||||||
.rounded_md()
|
// .px_4()
|
||||||
.when_some(self.selected_company.clone(), |this, company| {
|
// .rounded_md()
|
||||||
this.child(
|
// .when_some(self.selected_company.clone(), |this, company| {
|
||||||
div()
|
// this.child(
|
||||||
.flex_1()
|
// div()
|
||||||
.gap_2()
|
// .flex_1()
|
||||||
.child(
|
// .gap_2()
|
||||||
h_flex()
|
// .child(
|
||||||
.items_start()
|
// h_flex()
|
||||||
.justify_between()
|
// .items_start()
|
||||||
.child(div().text_3xl().mb_6().child(company.name.clone()))
|
// .justify_between()
|
||||||
.child(format!("{:.2}", company.last_done)),
|
// .child(div().text_3xl().mb_6().child(company.name.clone()))
|
||||||
)
|
// .child(format!("{:.2}", company.last_done)),
|
||||||
.child(company.industry.clone())
|
// )
|
||||||
.child(company.description.clone()),
|
// .child(company.industry.clone())
|
||||||
)
|
// .child(company.description.clone()),
|
||||||
}),
|
// )
|
||||||
)
|
// }),
|
||||||
|
// )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ impl Render for PopoverStory {
|
||||||
let form = self.form.clone();
|
let form = self.form.clone();
|
||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
|
.p_4()
|
||||||
.size_full()
|
.size_full()
|
||||||
.gap_6()
|
.gap_6()
|
||||||
.child(
|
.child(
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ impl TooltipStory {
|
||||||
impl Render for TooltipStory {
|
impl Render for TooltipStory {
|
||||||
fn render(&mut self, _cx: &mut gpui::ViewContext<Self>) -> impl gpui::IntoElement {
|
fn render(&mut self, _cx: &mut gpui::ViewContext<Self>) -> impl gpui::IntoElement {
|
||||||
v_flex()
|
v_flex()
|
||||||
.w(px(360.))
|
.p_4()
|
||||||
.gap_5()
|
.gap_5()
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::theme::ActiveTheme;
|
use crate::theme::{hsl, ActiveTheme};
|
||||||
use gpui::{hsla, point, px, BoxShadow, Styled, WindowContext};
|
use gpui::{hsla, point, px, BoxShadow, Styled, WindowContext};
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
|
||||||
|
|
@ -76,6 +76,26 @@ pub trait StyledExt: Styled + Sized {
|
||||||
fn elevation_3(self, cx: &WindowContext) -> Self {
|
fn elevation_3(self, cx: &WindowContext) -> Self {
|
||||||
elevated(self, cx, ElevationIndex::ModalSurface)
|
elevated(self, cx, ElevationIndex::ModalSurface)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Render a border with a width of 1px, color blue
|
||||||
|
fn debug_blue(self) -> Self {
|
||||||
|
self.border_1().border_color(gpui::blue())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render a border with a width of 1px, color yellow
|
||||||
|
fn debug_yellow(self) -> Self {
|
||||||
|
self.border_1().border_color(gpui::yellow())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render a border with a width of 1px, color green
|
||||||
|
fn debug_green(self) -> Self {
|
||||||
|
self.border_1().border_color(gpui::green())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render a border with a width of 1px, color pink
|
||||||
|
fn debug_pink(self) -> Self {
|
||||||
|
self.border_1().border_color(hsl(300., 100., 47.))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Styled> StyledExt for E {}
|
impl<E: Styled> StyledExt for E {}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ pub struct Tab {
|
||||||
impl Tab {
|
impl Tab {
|
||||||
pub fn new(id: impl Into<ElementId>, label: impl Into<AnyElement>) -> Self {
|
pub fn new(id: impl Into<ElementId>, label: impl Into<AnyElement>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base: div().id(id.into()),
|
base: div().id(id.into()).gap_1().py_1().px_3(),
|
||||||
label: label.into(),
|
label: label.into(),
|
||||||
disabled: false,
|
disabled: false,
|
||||||
selected: false,
|
selected: false,
|
||||||
|
|
@ -57,6 +57,12 @@ impl InteractiveElement for Tab {
|
||||||
|
|
||||||
impl StatefulInteractiveElement for Tab {}
|
impl StatefulInteractiveElement for Tab {}
|
||||||
|
|
||||||
|
impl Styled for Tab {
|
||||||
|
fn style(&mut self) -> &mut gpui::StyleRefinement {
|
||||||
|
self.base.style()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RenderOnce for Tab {
|
impl RenderOnce for Tab {
|
||||||
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
||||||
let (text_color, bg_color) = match (self.selected, self.disabled) {
|
let (text_color, bg_color) = match (self.selected, self.disabled) {
|
||||||
|
|
@ -68,14 +74,10 @@ impl RenderOnce for Tab {
|
||||||
self.base
|
self.base
|
||||||
.flex()
|
.flex()
|
||||||
.items_center()
|
.items_center()
|
||||||
.gap_2()
|
|
||||||
.h_full()
|
.h_full()
|
||||||
.flex_shrink_0()
|
.flex_shrink_0()
|
||||||
.overflow_scroll()
|
.overflow_scroll()
|
||||||
.cursor_pointer()
|
.cursor_pointer()
|
||||||
.py_1()
|
|
||||||
.px_3()
|
|
||||||
.min_w_16()
|
|
||||||
.text_color(text_color)
|
.text_color(text_color)
|
||||||
.bg(bg_color)
|
.bg(bg_color)
|
||||||
.when(self.selected, |this| this.rounded(px(6.)))
|
.when(self.selected, |this| this.rounded(px(6.)))
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
use crate::stock::h_flex;
|
use crate::stock::h_flex;
|
||||||
use crate::theme::ActiveTheme;
|
use crate::theme::ActiveTheme;
|
||||||
use gpui::prelude::FluentBuilder as _;
|
use gpui::prelude::FluentBuilder as _;
|
||||||
|
use gpui::InteractiveElement;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, AnyElement, Div, IntoElement, ParentElement, RenderOnce, ScrollHandle, SharedString,
|
div, AnyElement, Div, IntoElement, ParentElement, RenderOnce, ScrollHandle, SharedString,
|
||||||
StatefulInteractiveElement as _, WindowContext,
|
StatefulInteractiveElement as _, Styled, WindowContext,
|
||||||
};
|
};
|
||||||
use gpui::{InteractiveElement, Styled as _};
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
|
|
@ -19,7 +19,7 @@ pub struct TabBar {
|
||||||
impl TabBar {
|
impl TabBar {
|
||||||
pub fn new(id: impl Into<SharedString>) -> Self {
|
pub fn new(id: impl Into<SharedString>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base: div(),
|
base: div().h_10().p_1(),
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
children: SmallVec::new(),
|
children: SmallVec::new(),
|
||||||
scroll_handle: None,
|
scroll_handle: None,
|
||||||
|
|
@ -39,6 +39,12 @@ impl ParentElement for TabBar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Styled for TabBar {
|
||||||
|
fn style(&mut self) -> &mut gpui::StyleRefinement {
|
||||||
|
self.base.style()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RenderOnce for TabBar {
|
impl RenderOnce for TabBar {
|
||||||
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
||||||
let theme = cx.theme();
|
let theme = cx.theme();
|
||||||
|
|
@ -50,8 +56,6 @@ impl RenderOnce for TabBar {
|
||||||
.flex_none()
|
.flex_none()
|
||||||
.items_center()
|
.items_center()
|
||||||
.w_full()
|
.w_full()
|
||||||
.h_10()
|
|
||||||
.p_1()
|
|
||||||
.bg(theme.muted)
|
.bg(theme.muted)
|
||||||
.text_color(theme.muted_foreground)
|
.text_color(theme.muted_foreground)
|
||||||
.relative()
|
.relative()
|
||||||
|
|
|
||||||
|
|
@ -170,7 +170,7 @@ impl Colors {
|
||||||
ring: hsl(240.0, 5.9, 10.0),
|
ring: hsl(240.0, 5.9, 10.0),
|
||||||
selection: hsl(211.0, 97.0, 85.0),
|
selection: hsl(211.0, 97.0, 85.0),
|
||||||
scrollbar: Hsla::transparent_black(),
|
scrollbar: Hsla::transparent_black(),
|
||||||
scrollbar_thumb: hsl(240.0, 5.9, 90.0),
|
scrollbar_thumb: hsl(240.0, 5.9, 90.0).opacity(0.7),
|
||||||
panel: hsl(0.0, 0.0, 100.0),
|
panel: hsl(0.0, 0.0, 100.0),
|
||||||
drop_target: hsl(240.0, 65., 44.0).opacity(0.15),
|
drop_target: hsl(240.0, 65., 44.0).opacity(0.15),
|
||||||
}
|
}
|
||||||
|
|
@ -229,9 +229,9 @@ impl Colors {
|
||||||
ring: hsl(240.0, 4.9, 83.9),
|
ring: hsl(240.0, 4.9, 83.9),
|
||||||
selection: hsl(211.0, 97.0, 85.0),
|
selection: hsl(211.0, 97.0, 85.0),
|
||||||
scrollbar: Hsla::transparent_black(),
|
scrollbar: Hsla::transparent_black(),
|
||||||
scrollbar_thumb: hsl(240.0, 3.7, 15.9),
|
scrollbar_thumb: hsl(240.0, 3.7, 15.9).opacity(0.7),
|
||||||
panel: hsl(299.0, 2., 9.),
|
panel: hsl(299.0, 2., 9.),
|
||||||
drop_target: hsl(240.0, 65., 29.0).opacity(0.3),
|
drop_target: hsl(240.0, 89., 67.0).opacity(0.8),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,15 +45,17 @@ pub trait Panel: FocusableView + EventEmitter<PanelEvent> {
|
||||||
/// Return the position of the panel.
|
/// Return the position of the panel.
|
||||||
fn position(&self, cx: &WindowContext) -> DockPosition;
|
fn position(&self, cx: &WindowContext) -> DockPosition;
|
||||||
/// Return true if the panel can be positioned at the given position.
|
/// Return true if the panel can be positioned at the given position.
|
||||||
fn can_position(&self, position: DockPosition, cx: &WindowContext) -> bool;
|
fn can_position(&self, position: DockPosition) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
/// Set the position of the panel.
|
/// Set the position of the panel.
|
||||||
fn set_position(&mut self, position: DockPosition, cx: &mut WindowContext);
|
fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext<Self>) {}
|
||||||
/// Return the size of the panel.
|
/// Return the size of the panel.
|
||||||
fn size(&self, cx: &WindowContext) -> Pixels;
|
fn size(&self, cx: &WindowContext) -> Pixels;
|
||||||
/// Set the size of the panel.
|
/// Set the size of the panel.
|
||||||
fn set_size(&mut self, size: Option<Pixels>, cx: &mut WindowContext);
|
fn set_size(&mut self, size: Option<Pixels>, cx: &mut ViewContext<Self>) {}
|
||||||
/// Set the active state of the panel.
|
/// Set the active state of the panel.
|
||||||
fn set_active(&mut self, active: bool, cx: &mut WindowContext);
|
fn set_active(&mut self, active: bool, cx: &mut ViewContext<Self>) {}
|
||||||
fn icon(&self, _cx: &WindowContext) -> Option<IconName> {
|
fn icon(&self, _cx: &WindowContext) -> Option<IconName> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -62,7 +64,7 @@ pub trait Panel: FocusableView + EventEmitter<PanelEvent> {
|
||||||
}
|
}
|
||||||
fn set_zoomed(&mut self, _zoomed: bool, _cx: &mut ViewContext<Self>) {}
|
fn set_zoomed(&mut self, _zoomed: bool, _cx: &mut ViewContext<Self>) {}
|
||||||
fn starts_open(&self, _cx: &WindowContext) -> bool {
|
fn starts_open(&self, _cx: &WindowContext) -> bool {
|
||||||
false
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,7 +101,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn can_position(&self, position: DockPosition, cx: &WindowContext) -> bool {
|
fn can_position(&self, position: DockPosition, cx: &WindowContext) -> bool {
|
||||||
self.read(cx).can_position(position, cx)
|
self.read(cx).can_position(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_position(&self, position: DockPosition, cx: &mut WindowContext) {
|
fn set_position(&self, position: DockPosition, cx: &mut WindowContext) {
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,13 @@ impl Pane {
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_should_display_tab_bar<F>(&mut self, f: F)
|
||||||
|
where
|
||||||
|
F: 'static + Fn(&ViewContext<Pane>) -> bool,
|
||||||
|
{
|
||||||
|
self.should_display_tab_bar = Rc::new(f);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_custom_drop_handle<F>(&mut self, cx: &mut ViewContext<Self>, handle: F)
|
pub fn set_custom_drop_handle<F>(&mut self, cx: &mut ViewContext<Self>, handle: F)
|
||||||
where
|
where
|
||||||
F: 'static + Fn(&mut Pane, &dyn Any, &mut ViewContext<Pane>) -> ControlFlow<(), ()>,
|
F: 'static + Fn(&mut Pane, &dyn Any, &mut ViewContext<Pane>) -> ControlFlow<(), ()>,
|
||||||
|
|
@ -651,24 +658,30 @@ impl Pane {
|
||||||
},
|
},
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
// let indicator = render_item_indicator(item.boxed_clone(), cx);
|
|
||||||
let item_id = item.item_id();
|
let item_id = item.item_id();
|
||||||
let _is_first_item = ix == 0;
|
let _is_first_item = ix == 0;
|
||||||
let _is_last_item = ix == self.items.len() - 1;
|
let _is_last_item = ix == self.items.len() - 1;
|
||||||
let _position_relative_to_active_item = ix.cmp(&self.active_item_index);
|
let _position_relative_to_active_item = ix.cmp(&self.active_item_index);
|
||||||
|
|
||||||
Tab::new(ix, label)
|
Tab::new(ix, label)
|
||||||
|
.group("tab")
|
||||||
|
.px(px(5.))
|
||||||
|
.prefix(div().size_2().into_any_element())
|
||||||
|
.gap_0p5()
|
||||||
.suffix(
|
.suffix(
|
||||||
div()
|
div()
|
||||||
.id("close-tab")
|
.id("close-tab")
|
||||||
.p(px(1.5))
|
.p(px(0.5))
|
||||||
.rounded_md()
|
.rounded_lg()
|
||||||
.child(Icon::new(IconName::Close).size_3())
|
.invisible()
|
||||||
|
.child(Icon::new(IconName::Close).size_2())
|
||||||
.hover(|this| this.bg(cx.theme().accent.darken(0.1)))
|
.hover(|this| this.bg(cx.theme().accent.darken(0.1)))
|
||||||
.active(|this| this.bg(cx.theme().accent.darken(0.2)))
|
.active(|this| this.bg(cx.theme().accent.darken(0.2)))
|
||||||
.on_click(cx.listener(move |pane, _, cx| {
|
.on_click(cx.listener(move |pane, _, cx| {
|
||||||
pane.close_item_by_id(item_id, cx).detach_and_log_err(cx);
|
pane.close_item_by_id(item_id, cx).detach_and_log_err(cx);
|
||||||
}))
|
}))
|
||||||
|
.group_hover("tab", |this| this.visible())
|
||||||
.into_any(),
|
.into_any(),
|
||||||
)
|
)
|
||||||
.selected(is_active)
|
.selected(is_active)
|
||||||
|
|
@ -685,7 +698,11 @@ impl Pane {
|
||||||
},
|
},
|
||||||
|tab, cx| cx.new_view(|_| tab.clone()),
|
|tab, cx| cx.new_view(|_| tab.clone()),
|
||||||
)
|
)
|
||||||
.drag_over::<DraggedTab>(|tab, _, cx| tab.bg(cx.theme().drop_target))
|
.drag_over::<DraggedTab>(|tab, _, cx| {
|
||||||
|
tab.border_l_3()
|
||||||
|
.rounded_l_none()
|
||||||
|
.border_color(cx.theme().drop_target)
|
||||||
|
})
|
||||||
.drag_over::<DraggedSelection>(|tab, _, cx| tab.bg(cx.theme().drop_target))
|
.drag_over::<DraggedSelection>(|tab, _, cx| tab.bg(cx.theme().drop_target))
|
||||||
.when_some(self.can_drop_predicate.clone(), |this, p| {
|
.when_some(self.can_drop_predicate.clone(), |this, p| {
|
||||||
this.can_drop(move |a, cx| p(a, cx))
|
this.can_drop(move |a, cx| p(a, cx))
|
||||||
|
|
@ -722,6 +739,7 @@ impl Pane {
|
||||||
|
|
||||||
TabBar::new("tab-bar")
|
TabBar::new("tab-bar")
|
||||||
.track_scroll(self.tab_bar_scroll_handle.clone())
|
.track_scroll(self.tab_bar_scroll_handle.clone())
|
||||||
|
.gap(px(2.))
|
||||||
.when(self.has_focus(cx), |tab_bar| {
|
.when(self.has_focus(cx), |tab_bar| {
|
||||||
tab_bar.child({
|
tab_bar.child({
|
||||||
let render_tab_buttons = self.render_tab_bar_buttons.clone();
|
let render_tab_buttons = self.render_tab_bar_buttons.clone();
|
||||||
|
|
@ -739,8 +757,6 @@ impl Pane {
|
||||||
div()
|
div()
|
||||||
.id("tab-bar-drop-target")
|
.id("tab-bar-drop-target")
|
||||||
.min_w_6()
|
.min_w_6()
|
||||||
// HACK: This empty child is currently necessary to force the drop target to appear
|
|
||||||
// despite us setting a min width above.
|
|
||||||
.child("")
|
.child("")
|
||||||
.h_full()
|
.h_full()
|
||||||
.flex_grow()
|
.flex_grow()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue