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:
parent
c252eae32e
commit
baa07e935e
35 changed files with 154 additions and 117 deletions
42
crates/ui/src/elements/avatar.rs
Normal file
42
crates/ui/src/elements/avatar.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use gpui2::elements::img;
|
||||
use gpui2::style::StyleHelpers;
|
||||
use gpui2::{ArcCow, Element, IntoElement, ViewContext};
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::theme;
|
||||
|
||||
#[derive(Element, Clone)]
|
||||
pub struct Avatar {
|
||||
src: ArcCow<'static, str>,
|
||||
shape: Shape,
|
||||
}
|
||||
|
||||
pub fn avatar(src: impl Into<ArcCow<'static, str>>) -> Avatar {
|
||||
Avatar {
|
||||
src: src.into(),
|
||||
shape: Shape::Circle,
|
||||
}
|
||||
}
|
||||
|
||||
impl Avatar {
|
||||
pub fn shape(mut self, shape: Shape) -> Self {
|
||||
self.shape = shape;
|
||||
self
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
36
crates/ui/src/elements/details.rs
Normal file
36
crates/ui/src/elements/details.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use gpui2::elements::div;
|
||||
use gpui2::style::StyleHelpers;
|
||||
use gpui2::{Element, IntoElement, ParentElement, ViewContext};
|
||||
|
||||
use crate::theme;
|
||||
|
||||
#[derive(Element, Clone)]
|
||||
pub struct Details {
|
||||
text: &'static str,
|
||||
meta: Option<&'static str>,
|
||||
}
|
||||
|
||||
pub fn details(text: &'static str) -> Details {
|
||||
Details { text, meta: None }
|
||||
}
|
||||
|
||||
impl Details {
|
||||
pub fn meta_text(mut self, meta: &'static str) -> Self {
|
||||
self.meta = Some(meta);
|
||||
self
|
||||
}
|
||||
|
||||
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
let theme = theme(cx);
|
||||
|
||||
div()
|
||||
// .flex()
|
||||
// .w_full()
|
||||
.p_1()
|
||||
.gap_0p5()
|
||||
.text_xs()
|
||||
.text_color(theme.lowest.base.default.foreground)
|
||||
.child(self.text.clone())
|
||||
.children(self.meta.map(|m| m))
|
||||
}
|
||||
}
|
73
crates/ui/src/elements/icon.rs
Normal file
73
crates/ui/src/elements/icon.rs
Normal file
|
@ -0,0 +1,73 @@
|
|||
use gpui2::elements::svg;
|
||||
use gpui2::style::StyleHelpers;
|
||||
use gpui2::{Element, IntoElement, ViewContext};
|
||||
|
||||
use crate::theme;
|
||||
|
||||
// Icon::Hash
|
||||
// icon(IconAsset::Hash).color(IconColor::Warning)
|
||||
// Icon::new(IconAsset::Hash).color(IconColor::Warning)
|
||||
|
||||
#[derive(Default, PartialEq, Copy, Clone)]
|
||||
pub enum IconAsset {
|
||||
Ai,
|
||||
ArrowLeft,
|
||||
ArrowRight,
|
||||
#[default]
|
||||
ArrowUpRight,
|
||||
Bolt,
|
||||
Hash,
|
||||
File,
|
||||
Folder,
|
||||
FolderOpen,
|
||||
ChevronDown,
|
||||
ChevronUp,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
}
|
||||
|
||||
impl IconAsset {
|
||||
pub fn path(self) -> &'static str {
|
||||
match self {
|
||||
IconAsset::Ai => "icons/ai.svg",
|
||||
IconAsset::ArrowLeft => "icons/arrow_left.svg",
|
||||
IconAsset::ArrowRight => "icons/arrow_right.svg",
|
||||
IconAsset::ArrowUpRight => "icons/arrow_up_right.svg",
|
||||
IconAsset::Bolt => "icons/bolt.svg",
|
||||
IconAsset::Hash => "icons/hash.svg",
|
||||
IconAsset::ChevronDown => "icons/chevron_down.svg",
|
||||
IconAsset::ChevronUp => "icons/chevron_up.svg",
|
||||
IconAsset::ChevronLeft => "icons/chevron_left.svg",
|
||||
IconAsset::ChevronRight => "icons/chevron_right.svg",
|
||||
IconAsset::File => "icons/file_icons/file.svg",
|
||||
IconAsset::Folder => "icons/file_icons/folder.svg",
|
||||
IconAsset::FolderOpen => "icons/file_icons/folder_open.svg",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Element, Clone)]
|
||||
pub struct Icon {
|
||||
asset: IconAsset,
|
||||
}
|
||||
|
||||
pub fn icon(asset: IconAsset) -> Icon {
|
||||
Icon { asset }
|
||||
}
|
||||
|
||||
// impl Icon {
|
||||
// pub fn new(asset: IconAsset) -> Icon {
|
||||
// Icon { asset }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl Icon {
|
||||
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
let theme = theme(cx);
|
||||
|
||||
svg()
|
||||
.path(self.asset.path())
|
||||
.size_4()
|
||||
.fill(theme.lowest.base.default.foreground)
|
||||
}
|
||||
}
|
62
crates/ui/src/elements/icon_button.rs
Normal file
62
crates/ui/src/elements/icon_button.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
use gpui2::elements::{div, svg};
|
||||
use gpui2::style::{StyleHelpers, Styleable};
|
||||
use gpui2::{Element, IntoElement, ParentElement, ViewContext};
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::theme;
|
||||
|
||||
#[derive(Element)]
|
||||
pub struct IconButton {
|
||||
path: &'static str,
|
||||
variant: ButtonVariant,
|
||||
state: InteractionState,
|
||||
}
|
||||
|
||||
pub fn icon_button(path: &'static str) -> IconButton {
|
||||
IconButton {
|
||||
path,
|
||||
variant: ButtonVariant::default(),
|
||||
state: InteractionState::default(),
|
||||
}
|
||||
}
|
||||
|
||||
impl IconButton {
|
||||
pub fn variant(mut self, variant: ButtonVariant) -> Self {
|
||||
self.variant = variant;
|
||||
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);
|
||||
|
||||
let icon_color;
|
||||
|
||||
if self.state == InteractionState::Disabled {
|
||||
icon_color = theme.highest.base.disabled.foreground;
|
||||
} else {
|
||||
icon_color = theme.highest.base.default.foreground;
|
||||
}
|
||||
|
||||
let mut div = div();
|
||||
if self.variant == ButtonVariant::Filled {
|
||||
div = div.fill(theme.highest.on.default.background);
|
||||
}
|
||||
|
||||
div.w_7()
|
||||
.h_6()
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.rounded_md()
|
||||
.hover()
|
||||
.fill(theme.highest.base.hovered.background)
|
||||
.active()
|
||||
.fill(theme.highest.base.pressed.background)
|
||||
.child(svg().path(self.path).w_4().h_4().fill(icon_color))
|
||||
}
|
||||
}
|
33
crates/ui/src/elements/indicator.rs
Normal file
33
crates/ui/src/elements/indicator.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
use gpui2::elements::div;
|
||||
use gpui2::style::StyleHelpers;
|
||||
use gpui2::{Element, IntoElement, ViewContext};
|
||||
|
||||
use crate::theme;
|
||||
|
||||
#[derive(Element)]
|
||||
pub struct Indicator {
|
||||
player: usize,
|
||||
}
|
||||
|
||||
pub fn indicator() -> Indicator {
|
||||
Indicator { player: 0 }
|
||||
}
|
||||
|
||||
impl Indicator {
|
||||
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_color = theme.players[self.player].cursor;
|
||||
|
||||
div()
|
||||
.w_4()
|
||||
.h_1()
|
||||
.rounded_bl_sm()
|
||||
.rounded_br_sm()
|
||||
.fill(player_color)
|
||||
}
|
||||
}
|
100
crates/ui/src/elements/input.rs
Normal file
100
crates/ui/src/elements/input.rs
Normal file
|
@ -0,0 +1,100 @@
|
|||
use gpui2::elements::div;
|
||||
use gpui2::style::{StyleHelpers, Styleable};
|
||||
use gpui2::{Element, IntoElement, ParentElement, ViewContext};
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::theme;
|
||||
|
||||
#[derive(Element)]
|
||||
pub struct Input {
|
||||
placeholder: &'static str,
|
||||
value: String,
|
||||
state: InteractionState,
|
||||
variant: InputVariant,
|
||||
}
|
||||
|
||||
pub fn input(placeholder: &'static str) -> Input {
|
||||
Input {
|
||||
placeholder,
|
||||
value: "".to_string(),
|
||||
state: InteractionState::default(),
|
||||
variant: InputVariant::default(),
|
||||
}
|
||||
}
|
||||
|
||||
impl Input {
|
||||
pub fn value(mut self, value: String) -> Self {
|
||||
self.value = value;
|
||||
self
|
||||
}
|
||||
pub fn state(mut self, state: InteractionState) -> Self {
|
||||
self.state = state;
|
||||
self
|
||||
}
|
||||
pub fn variant(mut self, variant: InputVariant) -> Self {
|
||||
self.variant = variant;
|
||||
self
|
||||
}
|
||||
|
||||
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
let theme = theme(cx);
|
||||
|
||||
let text_el;
|
||||
let text_color;
|
||||
let background_color_default;
|
||||
let background_color_active;
|
||||
|
||||
let mut border_color_default = theme.middle.base.default.border;
|
||||
let mut border_color_hover = theme.middle.base.hovered.border;
|
||||
let mut border_color_active = theme.middle.base.pressed.border;
|
||||
let border_color_focus = theme.middle.base.pressed.background;
|
||||
|
||||
match self.variant {
|
||||
InputVariant::Ghost => {
|
||||
background_color_default = theme.middle.base.default.background;
|
||||
background_color_active = theme.middle.base.active.background;
|
||||
}
|
||||
InputVariant::Filled => {
|
||||
background_color_default = theme.middle.on.default.background;
|
||||
background_color_active = theme.middle.on.active.background;
|
||||
}
|
||||
};
|
||||
|
||||
if self.state == InteractionState::Focused {
|
||||
border_color_default = theme.players[0].cursor;
|
||||
border_color_hover = theme.players[0].cursor;
|
||||
border_color_active = theme.players[0].cursor;
|
||||
}
|
||||
|
||||
if self.state == InteractionState::Focused || self.state == InteractionState::Active {
|
||||
text_el = self.value.clone();
|
||||
text_color = theme.lowest.base.default.foreground;
|
||||
} else {
|
||||
text_el = self.placeholder.to_string().clone();
|
||||
text_color = theme.lowest.base.disabled.foreground;
|
||||
}
|
||||
|
||||
div()
|
||||
.h_7()
|
||||
.px_2()
|
||||
.border()
|
||||
.border_color(border_color_default)
|
||||
.fill(background_color_default)
|
||||
.hover()
|
||||
.border_color(border_color_hover)
|
||||
.active()
|
||||
.border_color(border_color_active)
|
||||
.fill(background_color_active)
|
||||
.flex()
|
||||
.items_center()
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.text_sm()
|
||||
.text_color(text_color)
|
||||
.child(text_el)
|
||||
.child(div().text_color(theme.players[0].cursor).child("|")),
|
||||
)
|
||||
}
|
||||
}
|
49
crates/ui/src/elements/label.rs
Normal file
49
crates/ui/src/elements/label.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
use gpui2::elements::div;
|
||||
use gpui2::style::StyleHelpers;
|
||||
use gpui2::{Element, IntoElement, ParentElement, ViewContext};
|
||||
|
||||
use crate::theme;
|
||||
|
||||
#[derive(Default, PartialEq, Copy, Clone)]
|
||||
pub enum LabelColor {
|
||||
#[default]
|
||||
Default,
|
||||
Created,
|
||||
Modified,
|
||||
Deleted,
|
||||
Hidden,
|
||||
}
|
||||
|
||||
#[derive(Element, Clone)]
|
||||
pub struct Label {
|
||||
label: &'static str,
|
||||
color: LabelColor,
|
||||
}
|
||||
|
||||
pub fn label(label: &'static str) -> Label {
|
||||
Label {
|
||||
label,
|
||||
color: LabelColor::Default,
|
||||
}
|
||||
}
|
||||
|
||||
impl Label {
|
||||
pub fn color(mut self, color: LabelColor) -> Self {
|
||||
self.color = color;
|
||||
self
|
||||
}
|
||||
|
||||
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
let theme = theme(cx);
|
||||
|
||||
let color = match self.color {
|
||||
LabelColor::Default => theme.lowest.base.default.foreground,
|
||||
LabelColor::Created => theme.lowest.positive.default.foreground,
|
||||
LabelColor::Modified => theme.lowest.warning.default.foreground,
|
||||
LabelColor::Deleted => theme.lowest.negative.default.foreground,
|
||||
LabelColor::Hidden => theme.lowest.variant.default.foreground,
|
||||
};
|
||||
|
||||
div().text_sm().text_color(color).child(self.label.clone())
|
||||
}
|
||||
}
|
82
crates/ui/src/elements/text_button.rs
Normal file
82
crates/ui/src/elements/text_button.rs
Normal file
|
@ -0,0 +1,82 @@
|
|||
use gpui2::elements::div;
|
||||
use gpui2::style::{StyleHelpers, Styleable};
|
||||
use gpui2::{Element, IntoElement, ParentElement, ViewContext};
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::theme;
|
||||
|
||||
#[derive(Element)]
|
||||
pub struct TextButton {
|
||||
label: &'static str,
|
||||
variant: ButtonVariant,
|
||||
state: InteractionState,
|
||||
}
|
||||
|
||||
pub fn text_button(label: &'static str) -> TextButton {
|
||||
TextButton {
|
||||
label,
|
||||
variant: ButtonVariant::default(),
|
||||
state: InteractionState::default(),
|
||||
}
|
||||
}
|
||||
|
||||
impl TextButton {
|
||||
pub fn variant(mut self, variant: ButtonVariant) -> Self {
|
||||
self.variant = variant;
|
||||
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);
|
||||
|
||||
let text_color_default;
|
||||
let text_color_hover;
|
||||
let text_color_active;
|
||||
|
||||
let background_color_default;
|
||||
let background_color_hover;
|
||||
let background_color_active;
|
||||
|
||||
let div = div();
|
||||
|
||||
match self.variant {
|
||||
ButtonVariant::Ghost => {
|
||||
text_color_default = theme.lowest.base.default.foreground;
|
||||
text_color_hover = theme.lowest.base.hovered.foreground;
|
||||
text_color_active = theme.lowest.base.pressed.foreground;
|
||||
background_color_default = theme.lowest.base.default.background;
|
||||
background_color_hover = theme.lowest.base.hovered.background;
|
||||
background_color_active = theme.lowest.base.pressed.background;
|
||||
}
|
||||
ButtonVariant::Filled => {
|
||||
text_color_default = theme.lowest.base.default.foreground;
|
||||
text_color_hover = theme.lowest.base.hovered.foreground;
|
||||
text_color_active = theme.lowest.base.pressed.foreground;
|
||||
background_color_default = theme.lowest.on.default.background;
|
||||
background_color_hover = theme.lowest.on.hovered.background;
|
||||
background_color_active = theme.lowest.on.pressed.background;
|
||||
}
|
||||
};
|
||||
div.h_6()
|
||||
.px_1()
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.rounded_md()
|
||||
.text_xs()
|
||||
.text_color(text_color_default)
|
||||
.fill(background_color_default)
|
||||
.hover()
|
||||
.text_color(text_color_hover)
|
||||
.fill(background_color_hover)
|
||||
.active()
|
||||
.text_color(text_color_active)
|
||||
.fill(background_color_active)
|
||||
.child(self.label.clone())
|
||||
}
|
||||
}
|
20
crates/ui/src/elements/tool_divider.rs
Normal file
20
crates/ui/src/elements/tool_divider.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use gpui2::elements::div;
|
||||
use gpui2::style::StyleHelpers;
|
||||
use gpui2::{Element, IntoElement, ViewContext};
|
||||
|
||||
use crate::theme;
|
||||
|
||||
#[derive(Element)]
|
||||
pub 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)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue