use std::sync::Arc;
use derive_where::derive_where;
use toasty::stmt::OrderByExpr;
use topcoat::{context::Cx, icon::IconData, view::*};
use super::{Column, ColumnBase, ColumnWidth, ReadFn, cell::icon_view, sort_order};
use crate::{Lens, display::Color, values::FormScalar};
#[derive_where(Clone, Debug)]
pub struct IconColumn<M, T> {
lens: Lens<M, T>,
base: ColumnBase,
sortable: bool,
#[derive_where(skip(Debug))]
icon: ReadFn<T, Option<IconData>>,
#[derive_where(skip(Debug))]
color: ReadFn<T, Option<Color>>,
}
impl<M, T> IconColumn<M, T>
where
M: toasty::schema::Model,
T: FormScalar + Send + Sync + 'static,
{
pub fn new(lens: Lens<M, T>) -> Self {
Self {
base: ColumnBase::new(lens.path(), ColumnWidth::Auto),
lens,
sortable: false,
icon: Arc::new(T::icon),
color: Arc::new(T::color),
}
}
pub fn icon(mut self, icon: impl Fn(&T) -> Option<IconData> + Send + Sync + 'static) -> Self {
self.icon = Arc::new(icon);
self
}
pub fn color(mut self, color: impl Fn(&T) -> Option<Color> + Send + Sync + 'static) -> Self {
self.color = Arc::new(color);
self
}
base_builders!(sortable);
}
impl<M, T> Column<M> for IconColumn<M, T>
where
M: toasty::schema::Model + Send + Sync + 'static,
T: FormScalar + Send + Sync + 'static,
{
base_column_methods!();
fn text(&self, cx: &Cx, row: &M) -> String {
self.lens.read(row).to_label().localize(cx)
}
fn cell<'a>(&self, cx: &'a Cx, row: &M) -> BoxView<'a> {
let value = self.lens.read(row);
let label = value.to_label().localize(cx);
match (self.icon)(value) {
Some(data) => icon_cell(cx, label, icon_view(cx, data, (self.color)(value))),
None => crate::schema::value_cell(cx, &label),
}
}
fn order_by(&self, descending: bool) -> Option<OrderByExpr> {
self.sortable
.then(|| sort_order(self.lens.path(), descending))
}
}
impl<M, T> crate::column::ColumnInternals<M> for IconColumn<M, T>
where
M: toasty::schema::Model + Send + Sync + 'static,
T: FormScalar + Send + Sync + 'static,
{
base_internals!(binding);
}
fn icon_cell<'a>(cx: &'a Cx, label: String, glyph: BoxView<'a>) -> BoxView<'a> {
view! {
<span class="inline-flex items-center" title=(label.clone())>
(glyph)
<span class="sr-only">(label)</span>
</span>
}
.boxed()
}