tablo_core/column/
rich_text.rs1use derive_where::derive_where;
4use topcoat::{context::Cx, view::*};
5
6use super::{Column, ColumnBase, ColumnWidth};
7use crate::{
8 Lens,
9 rich_text::{PROSE, clean, plain_text},
10 values::FormScalar,
11};
12
13#[derive_where(Clone, Debug)]
26pub struct RichTextColumn<M, T> {
27 lens: Lens<M, T>,
28 base: ColumnBase,
29 excerpt: usize,
30}
31
32impl<M, T> RichTextColumn<M, T>
33where
34 M: toasty::schema::Model,
35{
36 pub fn new(lens: Lens<M, T>) -> Self
38 where
39 T: toasty::schema::Field<Inner = String>,
40 {
41 Self {
42 base: ColumnBase::new(lens.path(), ColumnWidth::Grow),
43 lens,
44 excerpt: 120,
45 }
46 }
47
48 pub fn excerpt(mut self, chars: usize) -> Self {
51 self.excerpt = chars;
52 self
53 }
54
55 base_builders!();
56}
57
58impl<M, T> RichTextColumn<M, T>
59where
60 T: FormScalar,
61{
62 fn html(&self, row: &M) -> String {
63 clean(&self.lens.read(row).to_form())
64 }
65}
66
67impl<M, T> Column<M> for RichTextColumn<M, T>
68where
69 M: toasty::schema::Model + Send + Sync + 'static,
70 T: FormScalar + Send + Sync + 'static,
71{
72 base_column_methods!();
73
74 fn text(&self, _cx: &Cx, row: &M) -> String {
75 plain_text(&self.html(row))
76 }
77
78 fn cell<'a>(&self, cx: &'a Cx, row: &M) -> BoxView<'a> {
79 excerpt_cell(cx, &self.text(cx, row), self.excerpt)
80 }
81
82 fn entry<'a>(&self, cx: &'a Cx, row: &M) -> BoxView<'a> {
83 entry(cx, &self.label(), self.html(row))
84 }
85}
86
87impl<M, T> crate::column::ColumnInternals<M> for RichTextColumn<M, T>
88where
89 M: toasty::schema::Model + Send + Sync + 'static,
90 T: FormScalar + Send + Sync + 'static,
91{
92 base_internals!(binding);
93}
94
95fn excerpt_cell<'a>(cx: &'a Cx, text: &str, chars: usize) -> BoxView<'a> {
97 let text = text.replace('\n', " ");
98 let cut = match text.char_indices().nth(chars) {
99 Some((at, _)) => format!("{}…", text[..at].trim_end()),
100 None => text,
101 };
102 crate::schema::value_cell(cx, &cut)
103}
104
105fn entry<'a>(cx: &'a Cx, label: &crate::Text, html: String) -> BoxView<'a> {
107 let value = if html.is_empty() {
108 crate::schema::value_cell(cx, "")
109 } else {
110 let html = Unescaped::new_unchecked(html);
112 view! { <div class=(PROSE) data-rich-text-value="">(html)</div> }.boxed()
113 };
114 crate::schema::read_only(cx, label, value)
115}