jinya_ui/listing/
table.rs

1use yew::prelude::*;
2
3pub fn get_css<'a>() -> &'a str {
4    // language=CSS
5    "
6.jinya-table {
7    width: 100%;
8    border-spacing: 0;
9    border-collapse: collapse;
10}
11
12.jinya-table__column-header {
13    font-weight: bold;
14    border-bottom: 2px solid var(--primary-color);
15    text-align: left;
16    color: var(--primary-color);
17    padding: 0.75rem 0.75rem 0.5rem;
18}
19
20.jinya-table__row {
21    color: var(--primary-color);
22    cursor: pointer;
23    background: var(--white);
24    transition: all 0.3s;
25}
26
27.jinya-table__row:nth-child(2n + 1) {
28    background: var(--input-background-color);
29}
30
31.jinya-table__row:hover {
32    background: var(--disabled-color);
33}
34
35.jinya-table__row--selected {
36    background: var(--primary-color) !important;
37    color: var(--white) !important;
38}
39
40.jinya-table__cell {
41    padding: 0.75rem;
42}
43"
44}
45
46#[derive(Clone, PartialEq)]
47pub struct TableHeader {
48    pub title: String,
49    pub key: String,
50}
51
52pub enum Msg {
53    Select(usize),
54}
55
56#[derive(Clone, PartialEq)]
57pub struct TableCell {
58    pub key: String,
59    pub value: String,
60}
61
62#[derive(Clone, PartialEq)]
63pub struct TableRow {
64    cells: Vec<TableCell>,
65}
66
67impl TableRow {
68    pub fn new(cells: Vec<TableCell>) -> TableRow {
69        TableRow { cells }
70    }
71
72    pub fn remove_cell(&mut self, key: &str) {
73        let idx = self
74            .cells
75            .binary_search_by(|item| item.key.cmp(&key.to_string()));
76        if let Ok(index) = idx {
77            self.cells.remove(index);
78        }
79    }
80
81    pub fn add_cells(&mut self, cells: &mut Vec<TableCell>) {
82        self.cells.append(cells);
83    }
84}
85
86pub struct Table {
87    link: ComponentLink<Self>,
88    headers: Vec<TableHeader>,
89    rows: Vec<TableRow>,
90    on_select: Callback<usize>,
91    selected_index: Option<usize>,
92}
93
94#[derive(Clone, PartialEq, Properties)]
95pub struct TableProps {
96    pub headers: Vec<TableHeader>,
97    pub rows: Vec<TableRow>,
98    #[prop_or_default]
99    pub on_select: Callback<usize>,
100    #[prop_or(None)]
101    pub selected_index: Option<usize>,
102}
103
104impl Component for Table {
105    type Message = Msg;
106    type Properties = TableProps;
107
108    fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
109        Table {
110            link,
111            headers: props.headers,
112            rows: props.rows,
113            on_select: props.on_select,
114            selected_index: props.selected_index,
115        }
116    }
117
118    fn update(&mut self, msg: Self::Message) -> bool {
119        match msg {
120            Msg::Select(idx) => self.on_select.emit(idx),
121        }
122
123        true
124    }
125
126    fn change(&mut self, _props: Self::Properties) -> bool {
127        self.rows = _props.rows;
128        self.headers = _props.headers;
129        self.selected_index = _props.selected_index;
130        self.on_select = _props.on_select;
131
132        true
133    }
134
135    fn view(&self) -> Html {
136        html! {
137            <table class="jinya-table">
138                <thead>
139                    <tr>
140                        {for self.headers.iter().enumerate().map(|(_, header)| {
141                            html! {
142                                <th class="jinya-table__column-header">{&header.title}</th>
143                            }
144                        })}
145                    </tr>
146                </thead>
147                <tbody class="jinya-table__body">
148                    {for self.rows.iter().enumerate().map(|(idx, row)| {
149                        html! {
150                            <tr class=self.get_tr_class(idx) onclick=self.link.callback(move |_| Msg::Select(idx))>
151                                {for self.headers.iter().enumerate().map(move |(_, header)| {
152                                    html! {
153                                        <td class="jinya-table__cell">{self.get_cell_value(row, header)}</td>
154                                    }
155                                })}
156                            </tr>
157                        }
158                    })}
159                </tbody>
160            </table>
161        }
162    }
163}
164
165impl Table {
166    fn get_cell_value(&self, row: &TableRow, header: &TableHeader) -> String {
167        for cell in &row.cells {
168            if cell.key.eq(&header.key) {
169                return cell.value.to_string();
170            }
171        }
172
173        "".to_string()
174    }
175
176    fn get_tr_class(&self, idx: usize) -> String {
177        if self.selected_index.is_some() && idx == self.selected_index.unwrap() {
178            "jinya-table__row jinya-table__row--selected".to_string()
179        } else {
180            "jinya-table__row".to_string()
181        }
182    }
183}