tablo_core/column/
icon.rs1use std::sync::Arc;
4
5use derive_where::derive_where;
6use toasty::stmt::OrderByExpr;
7use topcoat::{context::Cx, icon::IconData, view::*};
8
9use super::{Column, ColumnBase, ColumnWidth, ReadFn, cell::icon_view, sort_order};
10use crate::{Lens, display::Color, values::FormScalar};
11
12#[derive_where(Clone, Debug)]
30pub struct IconColumn<M, T> {
31 lens: Lens<M, T>,
32 base: ColumnBase,
33 sortable: bool,
34 #[derive_where(skip(Debug))]
35 icon: ReadFn<T, Option<IconData>>,
36 #[derive_where(skip(Debug))]
37 color: ReadFn<T, Option<Color>>,
38}
39
40impl<M, T> IconColumn<M, T>
41where
42 M: toasty::schema::Model,
43 T: FormScalar + Send + Sync + 'static,
44{
45 pub fn new(lens: Lens<M, T>) -> Self {
47 Self {
48 base: ColumnBase::new(lens.path(), ColumnWidth::Auto),
49 lens,
50 sortable: false,
51 icon: Arc::new(T::icon),
52 color: Arc::new(T::color),
53 }
54 }
55
56 pub fn icon(mut self, icon: impl Fn(&T) -> Option<IconData> + Send + Sync + 'static) -> Self {
58 self.icon = Arc::new(icon);
59 self
60 }
61
62 pub fn color(mut self, color: impl Fn(&T) -> Option<Color> + Send + Sync + 'static) -> Self {
64 self.color = Arc::new(color);
65 self
66 }
67
68 base_builders!(sortable);
69}
70
71impl<M, T> Column<M> for IconColumn<M, T>
72where
73 M: toasty::schema::Model + Send + Sync + 'static,
74 T: FormScalar + Send + Sync + 'static,
75{
76 base_column_methods!();
77
78 fn text(&self, cx: &Cx, row: &M) -> String {
79 self.lens.read(row).to_label().localize(cx)
80 }
81
82 fn cell<'a>(&self, cx: &'a Cx, row: &M) -> BoxView<'a> {
83 let value = self.lens.read(row);
84 let label = value.to_label().localize(cx);
85 match (self.icon)(value) {
86 Some(data) => icon_cell(cx, label, icon_view(cx, data, (self.color)(value))),
87 None => crate::schema::value_cell(cx, &label),
88 }
89 }
90
91 fn order_by(&self, descending: bool) -> Option<OrderByExpr> {
92 self.sortable
93 .then(|| sort_order(self.lens.path(), descending))
94 }
95}
96
97impl<M, T> crate::column::ColumnInternals<M> for IconColumn<M, T>
98where
99 M: toasty::schema::Model + Send + Sync + 'static,
100 T: FormScalar + Send + Sync + 'static,
101{
102 base_internals!(binding);
103}
104
105fn icon_cell<'a>(cx: &'a Cx, label: String, glyph: BoxView<'a>) -> BoxView<'a> {
107 view! {
108 <span class="inline-flex items-center" title=(label.clone())>
109 (glyph)
110 <span class="sr-only">(label)</span>
111 </span>
112 }
113 .boxed()
114}