Extract UI elements from storybook into new ui crate (#3008)

This PR extracts the various UI elements from the `storybook` crate into
a new `ui` library crate.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2023-09-21 19:25:35 -04:00 committed by GitHub
parent c252eae32e
commit baa07e935e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 154 additions and 117 deletions

View file

@ -0,0 +1,28 @@
use gpui2::elements::div;
use gpui2::style::StyleHelpers;
use gpui2::{Element, IntoElement, ParentElement, ViewContext};
use crate::{theme, Avatar};
#[derive(Element)]
pub struct Facepile {
players: Vec<Avatar>,
}
pub fn facepile(players: Vec<Avatar>) -> Facepile {
Facepile { players }
}
impl Facepile {
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx);
let player_count = self.players.len();
let player_list = self.players.iter().enumerate().map(|(ix, player)| {
let isnt_last = ix < player_count - 1;
div()
.when(isnt_last, |div| div.neg_mr_1())
.child(player.clone())
});
div().p_1().flex().items_center().children(player_list)
}
}

View file

@ -0,0 +1,52 @@
use gpui2::elements::div;
use gpui2::style::StyleHelpers;
use gpui2::{Element, IntoElement, ParentElement, ViewContext};
use crate::{facepile, indicator, theme, Avatar};
#[derive(Element)]
pub struct FollowGroup {
player: usize,
players: Vec<Avatar>,
}
pub fn follow_group(players: Vec<Avatar>) -> FollowGroup {
FollowGroup { player: 0, players }
}
impl FollowGroup {
pub fn player(mut self, player: usize) -> Self {
self.player = player;
self
}
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx);
let player_bg = theme.players[self.player].selection;
div()
.h_full()
.flex()
.flex_col()
.gap_px()
.justify_center()
.child(
div()
.flex()
.justify_center()
.w_full()
.child(indicator().player(self.player)),
)
.child(
div()
.flex()
.items_center()
.justify_center()
.h_6()
.px_1()
.rounded_lg()
.fill(player_bg)
.child(facepile(self.players.clone())),
)
}
}

View file

@ -0,0 +1,88 @@
use gpui2::elements::div;
use gpui2::geometry::rems;
use gpui2::style::{StyleHelpers, Styleable};
use gpui2::{Element, IntoElement, ParentElement, ViewContext};
use crate::prelude::*;
use crate::{icon, theme, IconAsset, Label};
#[derive(Element)]
pub struct ListItem {
label: Label,
left_icon: Option<IconAsset>,
indent_level: u32,
state: InteractionState,
toggle: Option<ToggleState>,
}
pub fn list_item(label: Label) -> ListItem {
ListItem {
label,
indent_level: 0,
left_icon: None,
state: InteractionState::default(),
toggle: None,
}
}
impl ListItem {
pub fn indent_level(mut self, indent_level: u32) -> Self {
self.indent_level = indent_level;
self
}
pub fn set_toggle(mut self, toggle: ToggleState) -> Self {
self.toggle = Some(toggle);
self
}
pub fn left_icon(mut self, left_icon: Option<IconAsset>) -> Self {
self.left_icon = left_icon;
self
}
pub fn state(mut self, state: InteractionState) -> Self {
self.state = state;
self
}
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx);
div()
.fill(theme.middle.base.default.background)
.hover()
.fill(theme.middle.base.hovered.background)
.active()
.fill(theme.middle.base.pressed.background)
.relative()
.child(
div()
.h_7()
.px_2()
// .ml(rems(0.75 * self.indent_level as f32))
.children((0..self.indent_level).map(|_| {
div().w(rems(0.75)).h_full().flex().justify_center().child(
div()
.w_px()
.h_full()
.fill(theme.middle.base.default.border)
.hover()
.fill(theme.middle.warning.default.border)
.active()
.fill(theme.middle.negative.default.border),
)
}))
.flex()
.gap_2()
.items_center()
.children(match self.toggle {
Some(ToggleState::NotToggled) => Some(icon(IconAsset::ChevronRight)),
Some(ToggleState::Toggled) => Some(icon(IconAsset::ChevronDown)),
None => None,
})
.children(self.left_icon.map(|i| icon(i)))
.child(self.label.clone()),
)
}
}

View file

@ -0,0 +1,56 @@
use gpui2::elements::div;
use gpui2::style::{StyleHelpers, Styleable};
use gpui2::{Element, IntoElement, ParentElement, ViewContext};
use crate::theme;
#[derive(Element)]
pub struct Tab {
title: &'static str,
enabled: bool,
}
pub fn tab<V: 'static>(title: &'static str, enabled: bool) -> impl Element<V> {
Tab { title, enabled }
}
impl Tab {
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx);
div()
.px_2()
.py_0p5()
.flex()
.items_center()
.justify_center()
.rounded_lg()
.fill(if self.enabled {
theme.highest.on.default.background
} else {
theme.highest.base.default.background
})
.hover()
.fill(if self.enabled {
theme.highest.on.hovered.background
} else {
theme.highest.base.hovered.background
})
.active()
.fill(if self.enabled {
theme.highest.on.pressed.background
} else {
theme.highest.base.pressed.background
})
.child(
div()
.text_sm()
.text_color(if self.enabled {
theme.highest.base.default.foreground
} else {
theme.highest.variant.default.foreground
})
.child(self.title),
)
}
}