1use yew::prelude::*;
2use crate::components::common::{
3 Variant, TextAlign, TextWrap, TextTransform, FontWeight, FontStyle, TextDecoration,
4};
5#[derive(Properties, PartialEq)]
6pub struct HeadingProps {
7 #[prop_or_default]
8 pub children: Children,
9 #[prop_or_default]
10 pub level: HeadingLevel,
11 #[prop_or_default]
12 pub display: Option<DisplayHeading>,
13 #[prop_or_default]
14 pub lead: bool,
15 #[prop_or_default]
16 pub color: Option<Variant>,
17 #[prop_or_default]
18 pub text_align: Option<TextAlign>,
19 #[prop_or_default]
20 pub weight: Option<FontWeight>,
21 #[prop_or_default]
22 pub style: Option<FontStyle>,
23 #[prop_or_default]
24 pub transform: Option<TextTransform>,
25 #[prop_or_default]
26 pub decoration: Option<TextDecoration>,
27 #[prop_or_default]
28 pub wrap: Option<TextWrap>,
29 #[prop_or_default]
30 pub truncate: bool,
31 #[prop_or_default]
32 pub break_text: bool,
33 #[prop_or_default]
34 pub class: Option<AttrValue>,
35 #[prop_or_default]
36 pub node_ref: NodeRef,
37 #[prop_or_default]
38 pub id: Option<AttrValue>,
39}
40#[derive(Clone, Copy, PartialEq, Debug, Default)]
41pub enum HeadingLevel {
42 #[default]
43 H1,
44 H2,
45 H3,
46 H4,
47 H5,
48 H6,
49}
50impl HeadingLevel {
51 pub fn as_str(&self) -> &'static str {
52 match self {
53 HeadingLevel::H1 => "h1",
54 HeadingLevel::H2 => "h2",
55 HeadingLevel::H3 => "h3",
56 HeadingLevel::H4 => "h4",
57 HeadingLevel::H5 => "h5",
58 HeadingLevel::H6 => "h6",
59 }
60 }
61}
62#[derive(Clone, Copy, PartialEq, Debug)]
64pub enum DisplayHeading {
65 D1,
66 D2,
67 D3,
68 D4,
69 D5,
70 D6,
71}
72impl DisplayHeading {
73 pub fn as_str(&self) -> &'static str {
74 match self {
75 DisplayHeading::D1 => "display-1",
76 DisplayHeading::D2 => "display-2",
77 DisplayHeading::D3 => "display-3",
78 DisplayHeading::D4 => "display-4",
79 DisplayHeading::D5 => "display-5",
80 DisplayHeading::D6 => "display-6",
81 }
82 }
83}
84#[function_component(Heading)]
85pub fn heading(props: &HeadingProps) -> Html {
86 let mut classes = Classes::new();
87 if let Some(display) = &props.display {
88 classes.push(display.as_str());
89 }
90 if props.lead && matches!(props.level, HeadingLevel::H1) {
91 classes.push("lead");
92 }
93 if let Some(color) = &props.color {
94 classes.push(format!("text-{}", color.as_str()));
95 }
96 if let Some(align) = &props.text_align {
97 classes.push(align.as_str());
98 }
99 if let Some(weight) = &props.weight {
100 classes.push(weight.as_str());
101 }
102 if let Some(style) = &props.style {
103 classes.push(style.as_str());
104 }
105 if let Some(transform) = &props.transform {
106 classes.push(transform.as_str());
107 }
108 if let Some(decoration) = &props.decoration {
109 classes.push(decoration.as_str());
110 }
111 if let Some(wrap) = &props.wrap {
112 classes.push(wrap.as_str());
113 }
114 if props.truncate {
115 classes.push("text-truncate");
116 }
117 if props.break_text {
118 classes.push("text-break");
119 }
120 if let Some(class) = &props.class {
121 classes.push(class.to_string());
122 }
123 let tag = props.level.as_str();
124 html! {
125 <@ { tag } class = { classes } ref = { props.node_ref.clone() } id = { props.id
126 .clone() } > { for props.children.iter() } </@>
127 }
128}
129#[derive(Properties, PartialEq)]
130pub struct ParagraphProps {
131 #[prop_or_default]
132 pub children: Children,
133 #[prop_or_default]
134 pub color: Option<Variant>,
135 #[prop_or_default]
136 pub text_align: Option<TextAlign>,
137 #[prop_or_default]
138 pub weight: Option<FontWeight>,
139 #[prop_or_default]
140 pub style: Option<FontStyle>,
141 #[prop_or_default]
142 pub transform: Option<TextTransform>,
143 #[prop_or_default]
144 pub decoration: Option<TextDecoration>,
145 #[prop_or_default]
146 pub wrap: Option<TextWrap>,
147 #[prop_or_default]
148 pub truncate: bool,
149 #[prop_or_default]
150 pub break_text: bool,
151 #[prop_or_default]
152 pub class: Option<AttrValue>,
153 #[prop_or_default]
154 pub node_ref: NodeRef,
155}
156#[function_component(Paragraph)]
157pub fn paragraph(props: &ParagraphProps) -> Html {
158 let mut classes = Classes::new();
159 if let Some(color) = &props.color {
160 classes.push(format!("text-{}", color.as_str()));
161 }
162 if let Some(align) = &props.text_align {
163 classes.push(align.as_str());
164 }
165 if let Some(weight) = &props.weight {
166 classes.push(weight.as_str());
167 }
168 if let Some(style) = &props.style {
169 classes.push(style.as_str());
170 }
171 if let Some(transform) = &props.transform {
172 classes.push(transform.as_str());
173 }
174 if let Some(decoration) = &props.decoration {
175 classes.push(decoration.as_str());
176 }
177 if let Some(wrap) = &props.wrap {
178 classes.push(wrap.as_str());
179 }
180 if props.truncate {
181 classes.push("text-truncate");
182 }
183 if props.break_text {
184 classes.push("text-break");
185 }
186 if let Some(class) = &props.class {
187 classes.push(class.to_string());
188 }
189 html! {
190 < p class = { classes } ref = { props.node_ref.clone() } > { for props.children
191 .iter() } </ p >
192 }
193}
194#[derive(Properties, PartialEq)]
195pub struct BlockquoteProps {
196 #[prop_or_default]
197 pub children: Children,
198 #[prop_or_default]
199 pub footer: Option<Html>,
200 #[prop_or_default]
201 pub class: Option<AttrValue>,
202 #[prop_or_default]
203 pub node_ref: NodeRef,
204}
205#[function_component(Blockquote)]
206pub fn blockquote(props: &BlockquoteProps) -> Html {
207 let mut classes = Classes::new();
208 classes.push("blockquote");
209 if let Some(class) = &props.class {
210 classes.push(class.to_string());
211 }
212 html! {
213 < blockquote class = { classes } ref = { props.node_ref.clone() } > { for props
214 .children.iter() } if let Some(footer) = & props.footer { < footer class =
215 "blockquote-footer" > { footer.clone() } </ footer > } </ blockquote >
216 }
217}
218#[derive(Properties, PartialEq)]
219pub struct TextProps {
220 #[prop_or_default]
221 pub children: Children,
222 #[prop_or_default]
223 pub element: TextElement,
224 #[prop_or_default]
225 pub color: Option<Variant>,
226 #[prop_or_default]
227 pub text_align: Option<TextAlign>,
228 #[prop_or_default]
229 pub weight: Option<FontWeight>,
230 #[prop_or_default]
231 pub style: Option<FontStyle>,
232 #[prop_or_default]
233 pub transform: Option<TextTransform>,
234 #[prop_or_default]
235 pub decoration: Option<TextDecoration>,
236 #[prop_or_default]
237 pub wrap: Option<TextWrap>,
238 #[prop_or_default]
239 pub truncate: bool,
240 #[prop_or_default]
241 pub break_text: bool,
242 #[prop_or_default]
243 pub class: Option<AttrValue>,
244 #[prop_or_default]
245 pub node_ref: NodeRef,
246}
247#[derive(Clone, Copy, PartialEq, Debug, Default)]
248pub enum TextElement {
249 #[default]
250 Span,
251 Div,
252 Strong,
253 Em,
254 Small,
255 Mark,
256 Del,
257 Ins,
258 Sub,
259 Sup,
260 Code,
261 Kbd,
262 Samp,
263 Var,
264 Pre,
265}
266impl TextElement {
267 pub fn as_str(&self) -> &'static str {
268 match self {
269 TextElement::Span => "span",
270 TextElement::Div => "div",
271 TextElement::Strong => "strong",
272 TextElement::Em => "em",
273 TextElement::Small => "small",
274 TextElement::Mark => "mark",
275 TextElement::Del => "del",
276 TextElement::Ins => "ins",
277 TextElement::Sub => "sub",
278 TextElement::Sup => "sup",
279 TextElement::Code => "code",
280 TextElement::Kbd => "kbd",
281 TextElement::Samp => "samp",
282 TextElement::Var => "var",
283 TextElement::Pre => "pre",
284 }
285 }
286}
287#[function_component(Text)]
289pub fn text(props: &TextProps) -> Html {
290 let mut classes = Classes::new();
291 if let Some(color) = &props.color {
292 classes.push(format!("text-{}", color.as_str()));
293 }
294 if let Some(align) = &props.text_align {
295 classes.push(align.as_str());
296 }
297 if let Some(weight) = &props.weight {
298 classes.push(weight.as_str());
299 }
300 if let Some(style) = &props.style {
301 classes.push(style.as_str());
302 }
303 if let Some(transform) = &props.transform {
304 classes.push(transform.as_str());
305 }
306 if let Some(decoration) = &props.decoration {
307 classes.push(decoration.as_str());
308 }
309 if let Some(wrap) = &props.wrap {
310 classes.push(wrap.as_str());
311 }
312 if props.truncate {
313 classes.push("text-truncate");
314 }
315 if props.break_text {
316 classes.push("text-break");
317 }
318 if let Some(class) = &props.class {
319 classes.push(class.to_string());
320 }
321 let tag = props.element.as_str();
322 html! {
323 <@ { tag } class = { classes } ref = { props.node_ref.clone() } > { for props
324 .children.iter() } </@>
325 }
326}