use gpui::{AnyElement, Pixels, SharedString, div, prelude::*, px, relative};
use theme::{Theme, ink};
use crate::icons;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Width {
Fixed(Pixels),
Flex(f32),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Align {
Start,
End,
}
#[derive(Clone, Debug)]
pub struct Column {
pub label: SharedString,
pub width: Width,
pub align: Align,
}
impl Column {
pub fn new(label: impl Into<SharedString>, width: Width) -> Self {
Self {
label: label.into(),
width,
align: Align::Start,
}
}
pub fn align_end(mut self) -> Self {
self.align = Align::End;
self
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Sort {
pub column: usize,
pub ascending: bool,
}
pub fn next_sort(current: Option<Sort>, column: usize) -> Sort {
match current {
Some(sort) if sort.column == column => Sort {
column,
ascending: !sort.ascending,
},
_ => Sort {
column,
ascending: true,
},
}
}
const CELL_X: f32 = 12.0;
pub fn table(theme: &Theme) -> gpui::Div {
div()
.flex()
.flex_col()
.w_full()
.rounded(px(Theme::PANEL_RADIUS))
.border_1()
.border_color(theme.border)
.overflow_hidden()
}
pub fn header(theme: &Theme) -> gpui::Div {
div()
.flex()
.flex_row()
.items_center()
.w_full()
.bg(ink(0.03))
.border_b_1()
.border_color(theme.border)
}
pub fn header_cell(theme: &Theme, column: &Column, sorted: Option<bool>) -> gpui::Div {
cell_frame(column)
.py(px(8.0))
.gap(px(4.0))
.text_size(px(11.5))
.font_weight(gpui::FontWeight::MEDIUM)
.text_color(if sorted.is_some() {
theme.text
} else {
theme.text_muted
})
.cursor_pointer()
.child(column.label.clone())
.when_some(sorted, |cell, ascending| {
cell.child(
icons::icon(if ascending {
icons::ARROW_UP
} else {
icons::ARROW_DOWN
})
.size(px(11.0))
.text_color(theme.text_muted),
)
})
}
pub fn row(
theme: &Theme,
columns: &[Column],
first: bool,
selected: bool,
cells: Vec<AnyElement>,
) -> gpui::Div {
debug_assert_eq!(
cells.len(),
columns.len(),
"a table row must have one cell per column"
);
let mut row = div()
.flex()
.flex_row()
.items_center()
.w_full()
.when(!first, |row| {
row.border_t_1().border_color(theme.border.opacity(0.6))
})
.text_size(px(12.5))
.text_color(theme.text);
row = if selected {
row.bg(theme::card_selected_bg())
} else {
row.hover(|s| s.bg(ink(0.015)))
};
row.children(
columns
.iter()
.zip(cells)
.map(|(column, content)| cell_frame(column).py(px(9.0)).child(content)),
)
}
fn cell_frame(column: &Column) -> gpui::Div {
let cell = div()
.flex()
.flex_row()
.items_center()
.min_w_0()
.px(px(CELL_X))
.when(column.align == Align::End, |cell| cell.justify_end());
match column.width {
Width::Fixed(width) => cell.flex_none().w(width),
Width::Flex(weight) => cell
.flex_grow(weight)
.flex_shrink(1.0)
.flex_basis(relative(0.0)),
}
}