tablo_core/column/
boolean.rs1use derive_where::derive_where;
4use toasty::stmt::OrderByExpr;
5use topcoat::{context::Cx, icon::icon, view::*};
6
7use super::{Column, ColumnBase, ColumnWidth, sort_order};
8use crate::Lens;
9
10#[derive_where(Clone, Debug)]
18pub struct BooleanColumn<M> {
19 lens: Lens<M, bool>,
20 base: ColumnBase,
21 sortable: bool,
22 labels: (crate::Text, crate::Text),
23}
24
25impl<M> BooleanColumn<M>
26where
27 M: toasty::schema::Model,
28{
29 pub fn new(lens: Lens<M, bool>) -> Self {
31 Self {
32 base: ColumnBase::new(lens.path(), ColumnWidth::Auto),
33 lens,
34 sortable: false,
35 labels: (
36 crate::Text::message("tablo-yes"),
37 crate::Text::message("tablo-no"),
38 ),
39 }
40 }
41
42 base_builders!(sortable);
43
44 pub fn labels(mut self, yes: impl Into<crate::Text>, no: impl Into<crate::Text>) -> Self {
46 self.labels = (yes.into(), no.into());
47 self
48 }
49}
50
51impl<M> Column<M> for BooleanColumn<M>
52where
53 M: toasty::schema::Model + Send + Sync + 'static,
54{
55 base_column_methods!();
56
57 fn text(&self, cx: &Cx, row: &M) -> String {
58 if *self.lens.read(row) {
59 self.labels.0.localize(cx)
60 } else {
61 self.labels.1.localize(cx)
62 }
63 }
64
65 fn cell<'a>(&self, cx: &'a Cx, row: &M) -> BoxView<'a> {
66 boolean_cell(cx, *self.lens.read(row), self.text(cx, row))
67 }
68
69 fn order_by(&self, descending: bool) -> Option<OrderByExpr> {
70 self.sortable
71 .then(|| sort_order(self.lens.path(), descending))
72 }
73}
74
75impl<M> crate::column::ColumnInternals<M> for BooleanColumn<M>
76where
77 M: toasty::schema::Model + Send + Sync + 'static,
78{
79 base_internals!(binding);
80}
81
82pub(super) fn boolean_cell(cx: &Cx, value: bool, text: String) -> BoxView<'_> {
84 let (data, class) = if value {
86 (tablo_ui::icons::CIRCLE_CHECK, "size-4 text-success")
87 } else {
88 (tablo_ui::icons::MINUS, "size-4 text-muted-foreground/60")
89 };
90 view! {
91 <span class="inline-flex items-center" data-boolean=(value.to_string())>
92 icon(data: data, attrs: attributes! { class=(class) aria-hidden="true" })
93 <span class="sr-only">(text)</span>
94 </span>
95 }
96 .boxed()
97}