253 lines
7.4 KiB
Rust
253 lines
7.4 KiB
Rust
use ely_gpui_component::{
|
|
buttons::{Button, ButtonVariant, IconButton},
|
|
layout::{
|
|
Accordion, AccordionItem, Card, CardHeader, Collapsible, Fieldset, Frame, Panel, Section,
|
|
SplitPane, Well, resize_handle,
|
|
},
|
|
primitives::IconName,
|
|
theme::{ActiveTheme, ControlSize, Radius},
|
|
typography::{Caption, Label, Paragraph},
|
|
};
|
|
use gpui::{App, Axis, IntoElement, ParentElement, Styled, Window, div, px};
|
|
|
|
use super::basics::tile;
|
|
use crate::{
|
|
probe::probe,
|
|
ui::{code, row, section},
|
|
};
|
|
|
|
fn pane(label: &'static str, cx: &App) -> gpui::Div {
|
|
div()
|
|
.size_full()
|
|
.flex()
|
|
.items_center()
|
|
.justify_center()
|
|
.bg(cx.theme().colors.sunken)
|
|
.text_color(cx.theme().colors.fg_subtle)
|
|
.child(label)
|
|
}
|
|
|
|
fn frame(cx: &App) -> gpui::Div {
|
|
let theme = cx.theme();
|
|
div()
|
|
.w(px(560.0))
|
|
.h(px(220.0))
|
|
.overflow_hidden()
|
|
.rounded(theme.radius(Radius::Lg))
|
|
.border_1()
|
|
.border_color(theme.colors.border)
|
|
}
|
|
|
|
pub fn split_pane(cx: &App) -> impl IntoElement + use<> {
|
|
section(
|
|
"SplitPane",
|
|
"Drag a divider. Panes nest across and down.",
|
|
cx,
|
|
)
|
|
.child(probe(
|
|
"split",
|
|
frame(cx).child(
|
|
SplitPane::new("split-outer", Axis::Horizontal, px(96.0))
|
|
.sizes(&[0.3, 0.7])
|
|
.pane(pane("files", cx))
|
|
.pane(
|
|
SplitPane::new("split-inner", Axis::Vertical, px(48.0))
|
|
.pane(pane("editor", cx))
|
|
.pane(pane("terminal", cx)),
|
|
),
|
|
),
|
|
))
|
|
.child(code(
|
|
"ResizablePanel and ThreeColumnLayout are SplitPane.",
|
|
cx,
|
|
))
|
|
}
|
|
|
|
pub fn resize_handles(cx: &App) -> impl IntoElement + use<> {
|
|
section(
|
|
"ResizeHandle",
|
|
"A hairline with a wide grab. Hover lights it.",
|
|
cx,
|
|
)
|
|
.child(
|
|
row()
|
|
.gap_8()
|
|
.child(
|
|
div()
|
|
.h(px(80.0))
|
|
.child(resize_handle("handle-x", Axis::Horizontal, cx)),
|
|
)
|
|
.child(
|
|
div()
|
|
.w(px(160.0))
|
|
.child(resize_handle("handle-y", Axis::Vertical, cx)),
|
|
),
|
|
)
|
|
}
|
|
|
|
pub fn collapsible(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
|
|
let open = window.use_keyed_state("collapse-open", cx, |_, _| true);
|
|
let is_open = *open.read(cx);
|
|
section(
|
|
"Collapsible",
|
|
"Height animates to the measured content.",
|
|
cx,
|
|
)
|
|
.child(
|
|
div()
|
|
.w(px(420.0))
|
|
.flex()
|
|
.flex_col()
|
|
.gap_2()
|
|
.child(probe(
|
|
"collapse-toggle",
|
|
Button::new(
|
|
"collapse-toggle",
|
|
if is_open { "Collapse" } else { "Expand" },
|
|
)
|
|
.variant(ButtonVariant::Outline)
|
|
.trailing_icon(if is_open {
|
|
IconName::ChevronUp
|
|
} else {
|
|
IconName::ChevronDown
|
|
})
|
|
.on_click(move |_, _, cx| {
|
|
open.update(cx, |open, cx| {
|
|
*open = !*open;
|
|
cx.notify();
|
|
})
|
|
}),
|
|
))
|
|
.child(
|
|
Collapsible::new("collapse", is_open).child(
|
|
Paragraph::new(
|
|
"Content keeps its natural height. The frame grows to it, then lets go.",
|
|
)
|
|
.pt_2(),
|
|
),
|
|
),
|
|
)
|
|
}
|
|
|
|
pub fn accordion(cx: &App) -> impl IntoElement + use<> {
|
|
section(
|
|
"Accordion / AccordionItem",
|
|
"One open at a time. The chevron turns with it.",
|
|
cx,
|
|
)
|
|
.child(probe(
|
|
"accordion",
|
|
div().w(px(480.0)).child(
|
|
Accordion::new("faq")
|
|
.first_open()
|
|
.item(
|
|
AccordionItem::new("What is Ely?")
|
|
.child("A component library for gpui, in light and dark."),
|
|
)
|
|
.item(
|
|
AccordionItem::new("Does it animate?")
|
|
.child("Where motion explains a change, and nowhere else."),
|
|
)
|
|
.item(
|
|
AccordionItem::new("Can I theme it?")
|
|
.child("Every color, size and radius comes from one token set."),
|
|
),
|
|
),
|
|
))
|
|
}
|
|
|
|
pub fn card(cx: &App) -> impl IntoElement + use<> {
|
|
section(
|
|
"Card / CardHeader / CardBody / CardFooter",
|
|
"Flat: a hairline, no shadow.",
|
|
cx,
|
|
)
|
|
.child(
|
|
Card::new()
|
|
.w(px(380.0))
|
|
.header(
|
|
CardHeader::new("Storage")
|
|
.description("Across all workspaces")
|
|
.action(IconButton::new("card-more", IconName::Ellipsis).size(ControlSize::Sm)),
|
|
)
|
|
.child(Label::new("42.8 GB of 100 GB"))
|
|
.child(Caption::new("Media takes the most room."))
|
|
.footer(
|
|
div()
|
|
.flex()
|
|
.gap_2()
|
|
.child(Button::new("card-cancel", "Later").variant(ButtonVariant::Ghost))
|
|
.child(Button::new("card-go", "Manage").primary()),
|
|
),
|
|
)
|
|
}
|
|
|
|
pub fn panel(cx: &App) -> impl IntoElement + use<> {
|
|
section(
|
|
"Panel / PanelHeader",
|
|
"An app region: a quiet header bar and a body.",
|
|
cx,
|
|
)
|
|
.child(
|
|
Panel::new("Outline")
|
|
.w(px(320.0))
|
|
.h(px(160.0))
|
|
.action(IconButton::new("panel-filter", IconName::Filter).size(ControlSize::Sm))
|
|
.action(IconButton::new("panel-more", IconName::Ellipsis).size(ControlSize::Sm))
|
|
.child(
|
|
div()
|
|
.p_3()
|
|
.flex()
|
|
.flex_col()
|
|
.gap_2()
|
|
.child(tile("fn render", cx))
|
|
.child(tile("struct Theme", cx)),
|
|
),
|
|
)
|
|
}
|
|
|
|
pub fn section_demo(cx: &App) -> impl IntoElement + use<> {
|
|
section(
|
|
"Section / SectionHeader",
|
|
"A page block: title, note, action.",
|
|
cx,
|
|
)
|
|
.child(
|
|
Section::new("Members")
|
|
.w(px(520.0))
|
|
.description("People who can open this workspace.")
|
|
.action(Button::new("invite", "Invite").icon(IconName::Plus))
|
|
.child(
|
|
row()
|
|
.child(tile("Ada", cx))
|
|
.child(tile("Grace", cx))
|
|
.child(tile("Linus", cx)),
|
|
),
|
|
)
|
|
}
|
|
|
|
pub fn fieldset(cx: &App) -> impl IntoElement + use<> {
|
|
section("Group / Fieldset", "Related fields under one name.", cx).child(
|
|
Fieldset::new("Shipping address")
|
|
.w(px(420.0))
|
|
.child(tile("Street", cx))
|
|
.child(row().child(tile("City", cx)).child(tile("Postcode", cx))),
|
|
)
|
|
}
|
|
|
|
pub fn frame_demo(cx: &App) -> impl IntoElement + use<> {
|
|
section("Frame", "A bordered region with no fill.", cx).child(
|
|
Frame::new()
|
|
.w(px(320.0))
|
|
.child(Caption::new("Framed content sits on the page tone.")),
|
|
)
|
|
}
|
|
|
|
pub fn well(cx: &App) -> impl IntoElement + use<> {
|
|
section("Well", "A recessed region on the sunken tone.", cx).child(
|
|
Well::new()
|
|
.w(px(320.0))
|
|
.child(Caption::new("Wells hold secondary material.")),
|
|
)
|
|
}
|