Checkpoint
This commit is contained in:
parent
c545788168
commit
0d161519e4
11 changed files with 373 additions and 25 deletions
|
@ -4,11 +4,15 @@ use gpui2::{
|
||||||
};
|
};
|
||||||
use std::{marker::PhantomData, rc::Rc};
|
use std::{marker::PhantomData, rc::Rc};
|
||||||
|
|
||||||
|
mod avatar;
|
||||||
mod icon_button;
|
mod icon_button;
|
||||||
mod tab;
|
mod tab;
|
||||||
|
mod tool_divider;
|
||||||
|
|
||||||
pub(crate) use icon_button::{icon_button, ButtonVariant};
|
pub(crate) use avatar::avatar;
|
||||||
|
pub(crate) use icon_button::icon_button;
|
||||||
pub(crate) use tab::tab;
|
pub(crate) use tab::tab;
|
||||||
|
pub(crate) use tool_divider::tool_divider;
|
||||||
|
|
||||||
struct ButtonHandlers<V, D> {
|
struct ButtonHandlers<V, D> {
|
||||||
click: Option<Rc<dyn Fn(&mut V, &D, &mut EventContext<V>)>>,
|
click: Option<Rc<dyn Fn(&mut V, &D, &mut EventContext<V>)>>,
|
||||||
|
|
39
crates/storybook/src/components/avatar.rs
Normal file
39
crates/storybook/src/components/avatar.rs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
use crate::prelude::Shape;
|
||||||
|
use crate::theme::theme;
|
||||||
|
use gpui2::elements::img;
|
||||||
|
use gpui2::style::StyleHelpers;
|
||||||
|
use gpui2::{ArcCow, IntoElement};
|
||||||
|
use gpui2::{Element, ViewContext};
|
||||||
|
|
||||||
|
pub type UnknownString = ArcCow<'static, str>;
|
||||||
|
|
||||||
|
#[derive(Element)]
|
||||||
|
pub(crate) struct Avatar {
|
||||||
|
src: ArcCow<'static, str>,
|
||||||
|
shape: Shape,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn avatar<V: 'static>(src: impl Into<ArcCow<'static, str>>, shape: Shape) -> impl Element<V> {
|
||||||
|
Avatar {
|
||||||
|
src: src.into(),
|
||||||
|
shape,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Avatar {
|
||||||
|
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||||
|
let theme = theme(cx);
|
||||||
|
|
||||||
|
let mut img = img();
|
||||||
|
|
||||||
|
if self.shape == Shape::Circle {
|
||||||
|
img = img.rounded_full();
|
||||||
|
} else {
|
||||||
|
img = img.rounded_md();
|
||||||
|
}
|
||||||
|
|
||||||
|
img.uri(self.src.clone())
|
||||||
|
.size_4()
|
||||||
|
.fill(theme.middle.warning.default.foreground)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::prelude::{ButtonVariant, UIState};
|
||||||
use crate::theme::theme;
|
use crate::theme::theme;
|
||||||
use gpui2::elements::svg;
|
use gpui2::elements::svg;
|
||||||
use gpui2::style::{StyleHelpers, Styleable};
|
use gpui2::style::{StyleHelpers, Styleable};
|
||||||
|
@ -8,22 +9,33 @@ use gpui2::{Element, ParentElement, ViewContext};
|
||||||
pub(crate) struct IconButton {
|
pub(crate) struct IconButton {
|
||||||
path: &'static str,
|
path: &'static str,
|
||||||
variant: ButtonVariant,
|
variant: ButtonVariant,
|
||||||
|
state: UIState,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
pub fn icon_button<V: 'static>(
|
||||||
pub enum ButtonVariant {
|
path: &'static str,
|
||||||
Ghost,
|
variant: ButtonVariant,
|
||||||
Filled,
|
state: UIState,
|
||||||
|
) -> impl Element<V> {
|
||||||
|
IconButton {
|
||||||
|
path,
|
||||||
|
variant,
|
||||||
|
state,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn icon_button<V: 'static>(path: &'static str, variant: ButtonVariant) -> impl Element<V> {
|
|
||||||
IconButton { path, variant }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IconButton {
|
impl IconButton {
|
||||||
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||||
let theme = theme(cx);
|
let theme = theme(cx);
|
||||||
|
|
||||||
|
let icon_color;
|
||||||
|
|
||||||
|
if self.state == UIState::Disabled {
|
||||||
|
icon_color = theme.highest.base.disabled.foreground;
|
||||||
|
} else {
|
||||||
|
icon_color = theme.highest.base.default.foreground;
|
||||||
|
}
|
||||||
|
|
||||||
let mut div = div();
|
let mut div = div();
|
||||||
if self.variant == ButtonVariant::Filled {
|
if self.variant == ButtonVariant::Filled {
|
||||||
div = div.fill(theme.highest.on.default.background);
|
div = div.fill(theme.highest.on.default.background);
|
||||||
|
@ -39,12 +51,6 @@ impl IconButton {
|
||||||
.fill(theme.highest.base.hovered.background)
|
.fill(theme.highest.base.hovered.background)
|
||||||
.active()
|
.active()
|
||||||
.fill(theme.highest.base.pressed.background)
|
.fill(theme.highest.base.pressed.background)
|
||||||
.child(
|
.child(svg().path(self.path).w_4().h_4().fill(icon_color))
|
||||||
svg()
|
|
||||||
.path(self.path)
|
|
||||||
.w_4()
|
|
||||||
.h_4()
|
|
||||||
.fill(theme.highest.variant.default.foreground),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
crates/storybook/src/components/tool_divider.rs
Normal file
19
crates/storybook/src/components/tool_divider.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use crate::theme::theme;
|
||||||
|
use gpui2::style::StyleHelpers;
|
||||||
|
use gpui2::{elements::div, IntoElement};
|
||||||
|
use gpui2::{Element, ViewContext};
|
||||||
|
|
||||||
|
#[derive(Element)]
|
||||||
|
pub(crate) struct ToolDivider {}
|
||||||
|
|
||||||
|
pub fn tool_divider<V: 'static>() -> impl Element<V> {
|
||||||
|
ToolDivider {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToolDivider {
|
||||||
|
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||||
|
let theme = theme(cx);
|
||||||
|
|
||||||
|
div().w_px().h_3().fill(theme.lowest.base.default.border)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,7 @@
|
||||||
|
mod chat_panel;
|
||||||
mod tab_bar;
|
mod tab_bar;
|
||||||
|
mod title_bar;
|
||||||
|
|
||||||
|
pub(crate) use chat_panel::chat_panel;
|
||||||
pub(crate) use tab_bar::tab_bar;
|
pub(crate) use tab_bar::tab_bar;
|
||||||
|
pub(crate) use title_bar::title_bar;
|
||||||
|
|
74
crates/storybook/src/modules/chat_panel.rs
Normal file
74
crates/storybook/src/modules/chat_panel.rs
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use crate::components::icon_button;
|
||||||
|
use crate::prelude::{ButtonVariant, UIState};
|
||||||
|
use crate::theme::theme;
|
||||||
|
use gpui2::elements::div::ScrollState;
|
||||||
|
use gpui2::style::StyleHelpers;
|
||||||
|
use gpui2::{elements::div, IntoElement};
|
||||||
|
use gpui2::{Element, ParentElement, ViewContext};
|
||||||
|
|
||||||
|
#[derive(Element)]
|
||||||
|
pub struct ChatPanel<V: 'static> {
|
||||||
|
view_type: PhantomData<V>,
|
||||||
|
scroll_state: ScrollState,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn chat_panel<V: 'static>(scroll_state: ScrollState) -> ChatPanel<V> {
|
||||||
|
ChatPanel {
|
||||||
|
view_type: PhantomData,
|
||||||
|
scroll_state,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: 'static> ChatPanel<V> {
|
||||||
|
fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||||
|
let theme = theme(cx);
|
||||||
|
|
||||||
|
div()
|
||||||
|
.h_full()
|
||||||
|
.flex()
|
||||||
|
// Header
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.px_2()
|
||||||
|
.flex()
|
||||||
|
.gap_2()
|
||||||
|
// Nav Buttons
|
||||||
|
.child("#gpui2"),
|
||||||
|
)
|
||||||
|
// Chat Body
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.w_full()
|
||||||
|
.flex()
|
||||||
|
.flex_col()
|
||||||
|
.overflow_y_scroll(self.scroll_state.clone())
|
||||||
|
.child("body"),
|
||||||
|
)
|
||||||
|
// Composer
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.px_2()
|
||||||
|
.flex()
|
||||||
|
.gap_2()
|
||||||
|
// Nav Buttons
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.gap_px()
|
||||||
|
.child(icon_button(
|
||||||
|
"icons/plus.svg",
|
||||||
|
ButtonVariant::Ghost,
|
||||||
|
UIState::Default,
|
||||||
|
))
|
||||||
|
.child(icon_button(
|
||||||
|
"icons/split.svg",
|
||||||
|
ButtonVariant::Ghost,
|
||||||
|
UIState::Default,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use crate::components::{icon_button, tab, ButtonVariant};
|
use crate::components::{icon_button, tab};
|
||||||
|
use crate::prelude::{ButtonVariant, UIState};
|
||||||
use crate::theme::theme;
|
use crate::theme::theme;
|
||||||
use gpui2::elements::div::ScrollState;
|
use gpui2::elements::div::ScrollState;
|
||||||
use gpui2::style::StyleHelpers;
|
use gpui2::style::StyleHelpers;
|
||||||
|
@ -40,15 +41,23 @@ impl<V: 'static> TabBar<V> {
|
||||||
.flex()
|
.flex()
|
||||||
.items_center()
|
.items_center()
|
||||||
.gap_px()
|
.gap_px()
|
||||||
.child(icon_button("icons/arrow_left.svg", ButtonVariant::Filled))
|
.child(icon_button(
|
||||||
.child(icon_button("icons/arrow_right.svg", ButtonVariant::Ghost)),
|
"icons/arrow_left.svg",
|
||||||
|
ButtonVariant::Ghost,
|
||||||
|
UIState::Default,
|
||||||
|
))
|
||||||
|
.child(icon_button(
|
||||||
|
"icons/arrow_right.svg",
|
||||||
|
ButtonVariant::Ghost,
|
||||||
|
UIState::Disabled,
|
||||||
|
)),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
div().w_0().flex_1().h_full().child(
|
div().w_0().flex_1().h_full().child(
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
.gap_px()
|
.gap_8()
|
||||||
.overflow_x_scroll(self.scroll_state.clone())
|
.overflow_x_scroll(self.scroll_state.clone())
|
||||||
.child(tab("Cargo.toml", false))
|
.child(tab("Cargo.toml", false))
|
||||||
.child(tab("Channels Panel", true))
|
.child(tab("Channels Panel", true))
|
||||||
|
@ -74,8 +83,16 @@ impl<V: 'static> TabBar<V> {
|
||||||
.flex()
|
.flex()
|
||||||
.items_center()
|
.items_center()
|
||||||
.gap_px()
|
.gap_px()
|
||||||
.child(icon_button("icons/plus.svg", ButtonVariant::Ghost))
|
.child(icon_button(
|
||||||
.child(icon_button("icons/split.svg", ButtonVariant::Ghost)),
|
"icons/plus.svg",
|
||||||
|
ButtonVariant::Ghost,
|
||||||
|
UIState::Default,
|
||||||
|
))
|
||||||
|
.child(icon_button(
|
||||||
|
"icons/split.svg",
|
||||||
|
ButtonVariant::Ghost,
|
||||||
|
UIState::Default,
|
||||||
|
)),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
154
crates/storybook/src/modules/title_bar.rs
Normal file
154
crates/storybook/src/modules/title_bar.rs
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use crate::components::{avatar, icon_button, tool_divider};
|
||||||
|
use crate::prelude::{ButtonVariant, Shape, UIState};
|
||||||
|
use crate::theme::theme;
|
||||||
|
use gpui2::style::{StyleHelpers, Styleable};
|
||||||
|
use gpui2::{elements::div, IntoElement};
|
||||||
|
use gpui2::{Element, ParentElement, ViewContext};
|
||||||
|
|
||||||
|
#[derive(Element)]
|
||||||
|
pub struct TitleBar<V: 'static> {
|
||||||
|
view_type: PhantomData<V>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn title_bar<V: 'static>() -> TitleBar<V> {
|
||||||
|
TitleBar {
|
||||||
|
view_type: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: 'static> TitleBar<V> {
|
||||||
|
fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||||
|
let theme = theme(cx);
|
||||||
|
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.justify_between()
|
||||||
|
.w_full()
|
||||||
|
.h_8()
|
||||||
|
.fill(theme.lowest.base.default.background)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.h_full()
|
||||||
|
.gap_4()
|
||||||
|
.px_2()
|
||||||
|
// === Traffic Lights === //
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.gap_2()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.w_3()
|
||||||
|
.h_3()
|
||||||
|
.rounded_full()
|
||||||
|
.fill(theme.lowest.positive.default.foreground),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.w_3()
|
||||||
|
.h_3()
|
||||||
|
.rounded_full()
|
||||||
|
.fill(theme.lowest.warning.default.foreground),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.w_3()
|
||||||
|
.h_3()
|
||||||
|
.rounded_full()
|
||||||
|
.fill(theme.lowest.negative.default.foreground),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
// === Project Info === //
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.gap_1()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.h_full()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.justify_center()
|
||||||
|
.px_2()
|
||||||
|
.rounded_md()
|
||||||
|
.hover()
|
||||||
|
.fill(theme.lowest.base.hovered.background)
|
||||||
|
.active()
|
||||||
|
.fill(theme.lowest.base.pressed.background)
|
||||||
|
.child(div().text_sm().child("project")),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.h_full()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.justify_center()
|
||||||
|
.px_2()
|
||||||
|
.rounded_md()
|
||||||
|
.text_color(theme.lowest.variant.default.foreground)
|
||||||
|
.hover()
|
||||||
|
.fill(theme.lowest.base.hovered.background)
|
||||||
|
.active()
|
||||||
|
.fill(theme.lowest.base.pressed.background)
|
||||||
|
.child(div().text_sm().child("branch")),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.px_2()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.gap_1()
|
||||||
|
.child(icon_button(
|
||||||
|
"icons/stop_sharing.svg",
|
||||||
|
ButtonVariant::Ghost,
|
||||||
|
UIState::Default,
|
||||||
|
))
|
||||||
|
.child(icon_button(
|
||||||
|
"icons/exit.svg",
|
||||||
|
ButtonVariant::Ghost,
|
||||||
|
UIState::Default,
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.child(tool_divider())
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.px_2()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.gap_1()
|
||||||
|
.child(icon_button(
|
||||||
|
"icons/radix/mic.svg",
|
||||||
|
ButtonVariant::Ghost,
|
||||||
|
UIState::Default,
|
||||||
|
))
|
||||||
|
.child(icon_button(
|
||||||
|
"icons/radix/speaker-loud.svg",
|
||||||
|
ButtonVariant::Ghost,
|
||||||
|
UIState::Default,
|
||||||
|
))
|
||||||
|
.child(icon_button(
|
||||||
|
"icons/radix/desktop.svg",
|
||||||
|
ButtonVariant::Ghost,
|
||||||
|
UIState::Default,
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.child(div().px_2().flex().items_center().child(avatar(
|
||||||
|
"https://avatars.githubusercontent.com/u/1714999?v=4",
|
||||||
|
Shape::Squircle,
|
||||||
|
))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
26
crates/storybook/src/prelude.rs
Normal file
26
crates/storybook/src/prelude.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub enum ButtonVariant {
|
||||||
|
Ghost,
|
||||||
|
Filled,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub enum Shape {
|
||||||
|
Circle,
|
||||||
|
Squircle,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub enum UIState {
|
||||||
|
Default,
|
||||||
|
Hovered,
|
||||||
|
Active,
|
||||||
|
Focused,
|
||||||
|
Disabled,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub enum UIToggleState {
|
||||||
|
Default,
|
||||||
|
Enabled,
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ mod collab_panel;
|
||||||
mod components;
|
mod components;
|
||||||
mod element_ext;
|
mod element_ext;
|
||||||
mod modules;
|
mod modules;
|
||||||
|
mod prelude;
|
||||||
mod theme;
|
mod theme;
|
||||||
mod workspace;
|
mod workspace;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
use crate::{collab_panel::collab_panel, modules::tab_bar, theme::theme};
|
use crate::{
|
||||||
|
collab_panel::collab_panel,
|
||||||
|
modules::{chat_panel, tab_bar, title_bar},
|
||||||
|
theme::theme,
|
||||||
|
};
|
||||||
use gpui2::{
|
use gpui2::{
|
||||||
elements::{div, div::ScrollState, img, svg},
|
elements::{div, div::ScrollState, img, svg},
|
||||||
style::{StyleHelpers, Styleable},
|
style::{StyleHelpers, Styleable},
|
||||||
|
@ -30,7 +34,7 @@ impl WorkspaceElement {
|
||||||
.items_start()
|
.items_start()
|
||||||
.text_color(theme.lowest.base.default.foreground)
|
.text_color(theme.lowest.base.default.foreground)
|
||||||
.fill(theme.middle.base.default.background)
|
.fill(theme.middle.base.default.background)
|
||||||
.child(titlebar())
|
.child(title_bar())
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.flex_1()
|
.flex_1()
|
||||||
|
@ -52,7 +56,7 @@ impl WorkspaceElement {
|
||||||
.child(tab_bar(self.tab_bar_scroll_state.clone())),
|
.child(tab_bar(self.tab_bar_scroll_state.clone())),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.child(collab_panel(self.right_scroll_state.clone())),
|
.child(chat_panel(self.right_scroll_state.clone())),
|
||||||
)
|
)
|
||||||
.child(statusbar())
|
.child(statusbar())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue