jinya_ui/listing/
table.rs1use yew::prelude::*;
2
3pub fn get_css<'a>() -> &'a str {
4 "
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}