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