Add ui::table
(#20447)
This PR adds the `ui::Table` component. It has a rather simple API, but cells can contain either strings or elements, allowing for some complex uses. Example usage: ```rust Table::new(vec!["Product", "Price", "Stock"]) .width(px(600.)) .striped() .row(vec!["Laptop", "$999", "In Stock"]) .row(vec!["Phone", "$599", "Low Stock"]) .row(vec!["Tablet", "$399", "Out of Stock"]) ``` For more complex use cases, the table supports mixed content: ```rust Table::new(vec!["Status", "Name", "Priority", "Deadline", "Action"]) .width(px(840.)) .row(vec![ element_cell(Indicator::dot().color(Color::Success).into_any_element()), string_cell("Project A"), string_cell("High"), string_cell("2023-12-31"), element_cell(Button::new("view_a", "View").style(ButtonStyle::Filled).full_width().into_any_element()), ]) // ... more rows ``` Preview:  This component is pretty basic, improvements are welcome! Release Notes: - N/A
This commit is contained in:
parent
1f974d074e
commit
31a6ee0229
9 changed files with 306 additions and 24 deletions
|
@ -26,6 +26,7 @@ mod settings_group;
|
||||||
mod stack;
|
mod stack;
|
||||||
mod tab;
|
mod tab;
|
||||||
mod tab_bar;
|
mod tab_bar;
|
||||||
|
mod table;
|
||||||
mod tool_strip;
|
mod tool_strip;
|
||||||
mod tooltip;
|
mod tooltip;
|
||||||
|
|
||||||
|
@ -60,6 +61,7 @@ pub use settings_group::*;
|
||||||
pub use stack::*;
|
pub use stack::*;
|
||||||
pub use tab::*;
|
pub use tab::*;
|
||||||
pub use tab_bar::*;
|
pub use tab_bar::*;
|
||||||
|
pub use table::*;
|
||||||
pub use tool_strip::*;
|
pub use tool_strip::*;
|
||||||
pub use tooltip::*;
|
pub use tooltip::*;
|
||||||
|
|
||||||
|
|
|
@ -445,7 +445,7 @@ impl ComponentPreview for Button {
|
||||||
|
|
||||||
fn examples() -> Vec<ComponentExampleGroup<Self>> {
|
fn examples() -> Vec<ComponentExampleGroup<Self>> {
|
||||||
vec![
|
vec![
|
||||||
example_group(
|
example_group_with_title(
|
||||||
"Styles",
|
"Styles",
|
||||||
vec![
|
vec![
|
||||||
single_example("Default", Button::new("default", "Default")),
|
single_example("Default", Button::new("default", "Default")),
|
||||||
|
@ -463,7 +463,7 @@ impl ComponentPreview for Button {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
example_group(
|
example_group_with_title(
|
||||||
"Tinted",
|
"Tinted",
|
||||||
vec![
|
vec![
|
||||||
single_example(
|
single_example(
|
||||||
|
@ -488,7 +488,7 @@ impl ComponentPreview for Button {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
example_group(
|
example_group_with_title(
|
||||||
"States",
|
"States",
|
||||||
vec![
|
vec![
|
||||||
single_example("Default", Button::new("default_state", "Default")),
|
single_example("Default", Button::new("default_state", "Default")),
|
||||||
|
@ -502,7 +502,7 @@ impl ComponentPreview for Button {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
example_group(
|
example_group_with_title(
|
||||||
"With Icons",
|
"With Icons",
|
||||||
vec![
|
vec![
|
||||||
single_example(
|
single_example(
|
||||||
|
|
|
@ -123,7 +123,7 @@ impl ComponentPreview for Checkbox {
|
||||||
|
|
||||||
fn examples() -> Vec<ComponentExampleGroup<Self>> {
|
fn examples() -> Vec<ComponentExampleGroup<Self>> {
|
||||||
vec![
|
vec![
|
||||||
example_group(
|
example_group_with_title(
|
||||||
"Default",
|
"Default",
|
||||||
vec![
|
vec![
|
||||||
single_example(
|
single_example(
|
||||||
|
@ -140,7 +140,7 @@ impl ComponentPreview for Checkbox {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
example_group(
|
example_group_with_title(
|
||||||
"Disabled",
|
"Disabled",
|
||||||
vec![
|
vec![
|
||||||
single_example(
|
single_example(
|
||||||
|
|
|
@ -83,7 +83,7 @@ impl ComponentPreview for Facepile {
|
||||||
"https://avatars.githubusercontent.com/u/1714999?s=60&v=4",
|
"https://avatars.githubusercontent.com/u/1714999?s=60&v=4",
|
||||||
];
|
];
|
||||||
|
|
||||||
vec![example_group(
|
vec![example_group_with_title(
|
||||||
"Examples",
|
"Examples",
|
||||||
vec![
|
vec![
|
||||||
single_example(
|
single_example(
|
||||||
|
|
|
@ -6,7 +6,7 @@ use ui_macros::DerivePathStr;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
traits::component_preview::{example_group, ComponentExample, ComponentPreview},
|
traits::component_preview::{ComponentExample, ComponentPreview},
|
||||||
Indicator,
|
Indicator,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -510,7 +510,7 @@ impl ComponentPreview for Icon {
|
||||||
IconName::ArrowCircle,
|
IconName::ArrowCircle,
|
||||||
];
|
];
|
||||||
|
|
||||||
vec![example_group(
|
vec![example_group_with_title(
|
||||||
"Arrow Icons",
|
"Arrow Icons",
|
||||||
arrow_icons
|
arrow_icons
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
@ -91,7 +91,7 @@ impl ComponentPreview for Indicator {
|
||||||
|
|
||||||
fn examples() -> Vec<ComponentExampleGroup<Self>> {
|
fn examples() -> Vec<ComponentExampleGroup<Self>> {
|
||||||
vec![
|
vec![
|
||||||
example_group(
|
example_group_with_title(
|
||||||
"Types",
|
"Types",
|
||||||
vec![
|
vec![
|
||||||
single_example("Dot", Indicator::dot().color(Color::Info)),
|
single_example("Dot", Indicator::dot().color(Color::Info)),
|
||||||
|
@ -102,7 +102,7 @@ impl ComponentPreview for Indicator {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
example_group(
|
example_group_with_title(
|
||||||
"Examples",
|
"Examples",
|
||||||
vec![
|
vec![
|
||||||
single_example("Info", Indicator::dot().color(Color::Info)),
|
single_example("Info", Indicator::dot().color(Color::Info)),
|
||||||
|
|
239
crates/ui/src/components/table.rs
Normal file
239
crates/ui/src/components/table.rs
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
use crate::{prelude::*, Indicator};
|
||||||
|
use gpui::{div, AnyElement, FontWeight, IntoElement, Length};
|
||||||
|
|
||||||
|
/// A table component
|
||||||
|
#[derive(IntoElement)]
|
||||||
|
pub struct Table {
|
||||||
|
column_headers: Vec<SharedString>,
|
||||||
|
rows: Vec<Vec<TableCell>>,
|
||||||
|
column_count: usize,
|
||||||
|
striped: bool,
|
||||||
|
width: Length,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Table {
|
||||||
|
/// Create a new table with a column count equal to the
|
||||||
|
/// number of headers provided.
|
||||||
|
pub fn new(headers: Vec<impl Into<SharedString>>) -> Self {
|
||||||
|
let column_count = headers.len();
|
||||||
|
|
||||||
|
Table {
|
||||||
|
column_headers: headers.into_iter().map(Into::into).collect(),
|
||||||
|
column_count,
|
||||||
|
rows: Vec::new(),
|
||||||
|
striped: false,
|
||||||
|
width: Length::Auto,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a row to the table.
|
||||||
|
///
|
||||||
|
/// The row must have the same number of columns as the table.
|
||||||
|
pub fn row(mut self, items: Vec<impl Into<TableCell>>) -> Self {
|
||||||
|
if items.len() == self.column_count {
|
||||||
|
self.rows.push(items.into_iter().map(Into::into).collect());
|
||||||
|
} else {
|
||||||
|
// TODO: Log error: Row length mismatch
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds multiple rows to the table.
|
||||||
|
///
|
||||||
|
/// Each row must have the same number of columns as the table.
|
||||||
|
/// Rows that don't match the column count are ignored.
|
||||||
|
pub fn rows(mut self, rows: Vec<Vec<impl Into<TableCell>>>) -> Self {
|
||||||
|
for row in rows {
|
||||||
|
self = self.row(row);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn base_cell_style(cx: &WindowContext) -> Div {
|
||||||
|
div()
|
||||||
|
.px_1p5()
|
||||||
|
.flex_1()
|
||||||
|
.justify_start()
|
||||||
|
.text_ui(cx)
|
||||||
|
.whitespace_nowrap()
|
||||||
|
.text_ellipsis()
|
||||||
|
.overflow_hidden()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables row striping.
|
||||||
|
pub fn striped(mut self) -> Self {
|
||||||
|
self.striped = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the width of the table.
|
||||||
|
pub fn width(mut self, width: impl Into<Length>) -> Self {
|
||||||
|
self.width = width.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderOnce for Table {
|
||||||
|
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
||||||
|
let header = div()
|
||||||
|
.flex()
|
||||||
|
.flex_row()
|
||||||
|
.items_center()
|
||||||
|
.justify_between()
|
||||||
|
.w_full()
|
||||||
|
.p_2()
|
||||||
|
.border_b_1()
|
||||||
|
.border_color(cx.theme().colors().border)
|
||||||
|
.children(self.column_headers.into_iter().map(|h| {
|
||||||
|
Self::base_cell_style(cx)
|
||||||
|
.font_weight(FontWeight::SEMIBOLD)
|
||||||
|
.child(h)
|
||||||
|
}));
|
||||||
|
|
||||||
|
let row_count = self.rows.len();
|
||||||
|
let rows = self.rows.into_iter().enumerate().map(|(ix, row)| {
|
||||||
|
let is_last = ix == row_count - 1;
|
||||||
|
let bg = if ix % 2 == 1 && self.striped {
|
||||||
|
Some(cx.theme().colors().text.opacity(0.05))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
div()
|
||||||
|
.w_full()
|
||||||
|
.flex()
|
||||||
|
.flex_row()
|
||||||
|
.items_center()
|
||||||
|
.justify_between()
|
||||||
|
.px_1p5()
|
||||||
|
.py_1()
|
||||||
|
.when_some(bg, |row, bg| row.bg(bg))
|
||||||
|
.when(!is_last, |row| {
|
||||||
|
row.border_b_1().border_color(cx.theme().colors().border)
|
||||||
|
})
|
||||||
|
.children(row.into_iter().map(|cell| match cell {
|
||||||
|
TableCell::String(s) => Self::base_cell_style(cx).child(s),
|
||||||
|
TableCell::Element(e) => Self::base_cell_style(cx).child(e),
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
|
||||||
|
div()
|
||||||
|
.w(self.width)
|
||||||
|
.overflow_hidden()
|
||||||
|
.child(header)
|
||||||
|
.children(rows)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a cell in a table.
|
||||||
|
pub enum TableCell {
|
||||||
|
/// A cell containing a string value.
|
||||||
|
String(SharedString),
|
||||||
|
/// A cell containing a UI element.
|
||||||
|
Element(AnyElement),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a `TableCell` containing a string value.
|
||||||
|
pub fn string_cell(s: impl Into<SharedString>) -> TableCell {
|
||||||
|
TableCell::String(s.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a `TableCell` containing an element.
|
||||||
|
pub fn element_cell(e: impl Into<AnyElement>) -> TableCell {
|
||||||
|
TableCell::Element(e.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> From<E> for TableCell
|
||||||
|
where
|
||||||
|
E: Into<SharedString>,
|
||||||
|
{
|
||||||
|
fn from(e: E) -> Self {
|
||||||
|
TableCell::String(e.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ComponentPreview for Table {
|
||||||
|
fn description() -> impl Into<Option<&'static str>> {
|
||||||
|
"Used for showing tabular data. Tables may show both text and elements in their cells."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn example_label_side() -> ExampleLabelSide {
|
||||||
|
ExampleLabelSide::Top
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples() -> Vec<ComponentExampleGroup<Self>> {
|
||||||
|
vec![
|
||||||
|
example_group(vec![
|
||||||
|
single_example(
|
||||||
|
"Simple Table",
|
||||||
|
Table::new(vec!["Name", "Age", "City"])
|
||||||
|
.width(px(400.))
|
||||||
|
.row(vec!["Alice", "28", "New York"])
|
||||||
|
.row(vec!["Bob", "32", "San Francisco"])
|
||||||
|
.row(vec!["Charlie", "25", "London"]),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Two Column Table",
|
||||||
|
Table::new(vec!["Category", "Value"])
|
||||||
|
.width(px(300.))
|
||||||
|
.row(vec!["Revenue", "$100,000"])
|
||||||
|
.row(vec!["Expenses", "$75,000"])
|
||||||
|
.row(vec!["Profit", "$25,000"]),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
example_group(vec![single_example(
|
||||||
|
"Striped Table",
|
||||||
|
Table::new(vec!["Product", "Price", "Stock"])
|
||||||
|
.width(px(600.))
|
||||||
|
.striped()
|
||||||
|
.row(vec!["Laptop", "$999", "In Stock"])
|
||||||
|
.row(vec!["Phone", "$599", "Low Stock"])
|
||||||
|
.row(vec!["Tablet", "$399", "Out of Stock"])
|
||||||
|
.row(vec!["Headphones", "$199", "In Stock"]),
|
||||||
|
)]),
|
||||||
|
example_group_with_title(
|
||||||
|
"Mixed Content Table",
|
||||||
|
vec![single_example(
|
||||||
|
"Table with Elements",
|
||||||
|
Table::new(vec!["Status", "Name", "Priority", "Deadline", "Action"])
|
||||||
|
.width(px(840.))
|
||||||
|
.row(vec![
|
||||||
|
element_cell(Indicator::dot().color(Color::Success).into_any_element()),
|
||||||
|
string_cell("Project A"),
|
||||||
|
string_cell("High"),
|
||||||
|
string_cell("2023-12-31"),
|
||||||
|
element_cell(
|
||||||
|
Button::new("view_a", "View")
|
||||||
|
.style(ButtonStyle::Filled)
|
||||||
|
.full_width()
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.row(vec![
|
||||||
|
element_cell(Indicator::dot().color(Color::Warning).into_any_element()),
|
||||||
|
string_cell("Project B"),
|
||||||
|
string_cell("Medium"),
|
||||||
|
string_cell("2024-03-15"),
|
||||||
|
element_cell(
|
||||||
|
Button::new("view_b", "View")
|
||||||
|
.style(ButtonStyle::Filled)
|
||||||
|
.full_width()
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.row(vec![
|
||||||
|
element_cell(Indicator::dot().color(Color::Error).into_any_element()),
|
||||||
|
string_cell("Project C"),
|
||||||
|
string_cell("Low"),
|
||||||
|
string_cell("2024-06-30"),
|
||||||
|
element_cell(
|
||||||
|
Button::new("view_c", "View")
|
||||||
|
.style(ButtonStyle::Filled)
|
||||||
|
.full_width()
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
)],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,20 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use gpui::{AnyElement, SharedString};
|
use gpui::{AnyElement, SharedString};
|
||||||
|
|
||||||
|
/// Which side of the preview to show labels on
|
||||||
|
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum ExampleLabelSide {
|
||||||
|
/// Left side
|
||||||
|
Left,
|
||||||
|
/// Right side
|
||||||
|
Right,
|
||||||
|
/// Top side
|
||||||
|
Top,
|
||||||
|
#[default]
|
||||||
|
/// Bottom side
|
||||||
|
Bottom,
|
||||||
|
}
|
||||||
|
|
||||||
/// Implement this trait to enable rich UI previews with metadata in the Theme Preview tool.
|
/// Implement this trait to enable rich UI previews with metadata in the Theme Preview tool.
|
||||||
pub trait ComponentPreview: IntoElement {
|
pub trait ComponentPreview: IntoElement {
|
||||||
fn title() -> &'static str {
|
fn title() -> &'static str {
|
||||||
|
@ -12,6 +26,10 @@ pub trait ComponentPreview: IntoElement {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn example_label_side() -> ExampleLabelSide {
|
||||||
|
ExampleLabelSide::default()
|
||||||
|
}
|
||||||
|
|
||||||
fn examples() -> Vec<ComponentExampleGroup<Self>>;
|
fn examples() -> Vec<ComponentExampleGroup<Self>>;
|
||||||
|
|
||||||
fn component_previews() -> Vec<AnyElement> {
|
fn component_previews() -> Vec<AnyElement> {
|
||||||
|
@ -62,7 +80,9 @@ pub trait ComponentPreview: IntoElement {
|
||||||
fn render_example_group(group: ComponentExampleGroup<Self>) -> AnyElement {
|
fn render_example_group(group: ComponentExampleGroup<Self>) -> AnyElement {
|
||||||
v_flex()
|
v_flex()
|
||||||
.gap_2()
|
.gap_2()
|
||||||
.child(Label::new(group.title).size(LabelSize::Small))
|
.when_some(group.title, |this, title| {
|
||||||
|
this.child(Headline::new(title).size(HeadlineSize::Small))
|
||||||
|
})
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.gap_6()
|
.gap_6()
|
||||||
|
@ -73,8 +93,16 @@ pub trait ComponentPreview: IntoElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_example(example: ComponentExample<Self>) -> AnyElement {
|
fn render_example(example: ComponentExample<Self>) -> AnyElement {
|
||||||
v_flex()
|
let base = div().flex();
|
||||||
.gap_1()
|
|
||||||
|
let base = match Self::example_label_side() {
|
||||||
|
ExampleLabelSide::Right => base.flex_row(),
|
||||||
|
ExampleLabelSide::Left => base.flex_row_reverse(),
|
||||||
|
ExampleLabelSide::Bottom => base.flex_col(),
|
||||||
|
ExampleLabelSide::Top => base.flex_col_reverse(),
|
||||||
|
};
|
||||||
|
|
||||||
|
base.gap_1()
|
||||||
.child(example.element)
|
.child(example.element)
|
||||||
.child(
|
.child(
|
||||||
Label::new(example.variant_name)
|
Label::new(example.variant_name)
|
||||||
|
@ -103,15 +131,22 @@ impl<T> ComponentExample<T> {
|
||||||
|
|
||||||
/// A group of component examples.
|
/// A group of component examples.
|
||||||
pub struct ComponentExampleGroup<T> {
|
pub struct ComponentExampleGroup<T> {
|
||||||
pub title: SharedString,
|
pub title: Option<SharedString>,
|
||||||
pub examples: Vec<ComponentExample<T>>,
|
pub examples: Vec<ComponentExample<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ComponentExampleGroup<T> {
|
impl<T> ComponentExampleGroup<T> {
|
||||||
/// Create a new group of examples with the given title.
|
/// Create a new group of examples with the given title.
|
||||||
pub fn new(title: impl Into<SharedString>, examples: Vec<ComponentExample<T>>) -> Self {
|
pub fn new(examples: Vec<ComponentExample<T>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
title: title.into(),
|
title: None,
|
||||||
|
examples,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_title(title: impl Into<SharedString>, examples: Vec<ComponentExample<T>>) -> Self {
|
||||||
|
Self {
|
||||||
|
title: Some(title.into()),
|
||||||
examples,
|
examples,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,10 +157,15 @@ pub fn single_example<T>(variant_name: impl Into<SharedString>, example: T) -> C
|
||||||
ComponentExample::new(variant_name, example)
|
ComponentExample::new(variant_name, example)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a group of examples
|
/// Create a group of examples without a title
|
||||||
pub fn example_group<T>(
|
pub fn example_group<T>(examples: Vec<ComponentExample<T>>) -> ComponentExampleGroup<T> {
|
||||||
|
ComponentExampleGroup::new(examples)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a group of examples with a title
|
||||||
|
pub fn example_group_with_title<T>(
|
||||||
title: impl Into<SharedString>,
|
title: impl Into<SharedString>,
|
||||||
examples: Vec<ComponentExample<T>>,
|
examples: Vec<ComponentExample<T>>,
|
||||||
) -> ComponentExampleGroup<T> {
|
) -> ComponentExampleGroup<T> {
|
||||||
ComponentExampleGroup::new(title, examples)
|
ComponentExampleGroup::with_title(title, examples)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#![allow(unused, dead_code)]
|
#![allow(unused, dead_code)]
|
||||||
use gpui::{actions, AppContext, EventEmitter, FocusHandle, FocusableView, Hsla};
|
use gpui::{actions, hsla, AnyElement, AppContext, EventEmitter, FocusHandle, FocusableView, Hsla};
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
use theme::all_theme_colors;
|
use theme::all_theme_colors;
|
||||||
use ui::{
|
use ui::{
|
||||||
prelude::*, utils::calculate_contrast_ratio, AudioStatus, Availability, Avatar,
|
element_cell, prelude::*, string_cell, utils::calculate_contrast_ratio, AudioStatus,
|
||||||
AvatarAudioStatusIndicator, AvatarAvailabilityIndicator, ButtonLike, Checkbox, ElevationIndex,
|
Availability, Avatar, AvatarAudioStatusIndicator, AvatarAvailabilityIndicator, ButtonLike,
|
||||||
Facepile, Indicator, TintColor, Tooltip,
|
Checkbox, ElevationIndex, Facepile, Indicator, Table, TintColor, Tooltip,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{Item, Workspace};
|
use crate::{Item, Workspace};
|
||||||
|
@ -514,6 +514,7 @@ impl ThemePreview {
|
||||||
.child(Button::render_component_previews(cx))
|
.child(Button::render_component_previews(cx))
|
||||||
.child(Indicator::render_component_previews(cx))
|
.child(Indicator::render_component_previews(cx))
|
||||||
.child(Icon::render_component_previews(cx))
|
.child(Icon::render_component_previews(cx))
|
||||||
|
.child(Table::render_component_previews(cx))
|
||||||
.child(self.render_avatars(cx))
|
.child(self.render_avatars(cx))
|
||||||
.child(self.render_buttons(layer, cx))
|
.child(self.render_buttons(layer, cx))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue