1use gpui::prelude::*;
4use gpui::{div, px, App, Div, FontWeight, Hsla, IntoElement, SharedString, Window};
5
6use crate::theme::{theme, ColorName, Size};
7
8fn cell(value: SharedString, color: Hsla, weight: FontWeight, font: f32) -> Div {
11 div()
12 .flex_1()
13 .px(px(12.0))
14 .py(px(8.0))
15 .text_size(px(font))
16 .text_color(color)
17 .font_weight(weight)
18 .child(value)
19}
20
21#[derive(IntoElement)]
24pub struct Table {
25 head: Vec<SharedString>,
26 rows: Vec<Vec<SharedString>>,
27 striped: bool,
28 highlight_on_hover: bool,
29 with_border: bool,
30}
31
32impl Table {
33 pub fn new() -> Self {
34 Table {
35 head: Vec::new(),
36 rows: Vec::new(),
37 striped: false,
38 highlight_on_hover: false,
39 with_border: false,
40 }
41 }
42
43 pub fn head<I, S>(mut self, head: I) -> Self
44 where
45 I: IntoIterator<Item = S>,
46 S: Into<SharedString>,
47 {
48 self.head = head.into_iter().map(Into::into).collect();
49 self
50 }
51
52 pub fn row<I, S>(mut self, row: I) -> Self
53 where
54 I: IntoIterator<Item = S>,
55 S: Into<SharedString>,
56 {
57 self.rows.push(row.into_iter().map(Into::into).collect());
58 self
59 }
60
61 pub fn striped(mut self, striped: bool) -> Self {
62 self.striped = striped;
63 self
64 }
65
66 pub fn highlight_on_hover(mut self, highlight: bool) -> Self {
67 self.highlight_on_hover = highlight;
68 self
69 }
70
71 pub fn with_border(mut self, with_border: bool) -> Self {
72 self.with_border = with_border;
73 self
74 }
75}
76
77impl Default for Table {
78 fn default() -> Self {
79 Table::new()
80 }
81}
82
83impl RenderOnce for Table {
84 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
85 let t = theme(cx);
86 let font = t.font_size(Size::Sm);
87 let text = t.text().hsla();
88 let dimmed = t.dimmed().hsla();
89 let line = t.border().hsla();
90 let stripe = t.surface_hover().hsla();
91 let hover = t.color(ColorName::Gray, if t.scheme.is_dark() { 6 } else { 1 }).hsla();
92 let radius = t.radius(Size::Sm);
93 let striped = self.striped;
94 let highlight = self.highlight_on_hover;
95
96 let header = div()
97 .flex()
98 .border_b_1()
99 .border_color(line)
100 .children(
101 self.head
102 .into_iter()
103 .map(move |h| cell(h, dimmed, FontWeight::SEMIBOLD, font)),
104 );
105
106 let body = self.rows.into_iter().enumerate().map(move |(i, row)| {
107 let mut tr = div().flex().border_b_1().border_color(line).children(
108 row.into_iter()
109 .map(move |c| cell(c, text, FontWeight::NORMAL, font)),
110 );
111 if striped && i % 2 == 1 {
112 tr = tr.bg(stripe);
113 }
114 if highlight {
115 tr.id(("guise-table-row", i))
116 .hover(move |s| s.bg(hover))
117 .into_any_element()
118 } else {
119 tr.into_any_element()
120 }
121 });
122
123 let mut table = div()
124 .flex()
125 .flex_col()
126 .rounded(px(radius))
127 .child(header)
128 .children(body);
129 if self.with_border {
130 table = table.border_1().border_color(line);
131 }
132 table
133 }
134}