elmethis_json_component_types/
lib.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
4#[serde(untagged)]
5pub enum Component {
6    InlineComponent(InlineComponent),
7    BlockComponent(BlockComponent),
8}
9
10#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
11#[serde(untagged)]
12pub enum InlineComponent {
13    Text(Text),
14    Icon(Icon),
15}
16
17#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
18#[serde(untagged)]
19pub enum BlockComponent {
20    Heading(Heading),
21    Paragraph(Paragraph),
22    ListItem(ListItem),
23    List(List),
24    BlockQuote(BlockQuote),
25    Callout(Callout),
26    Divider(Divider),
27    Toggle(Toggle),
28    Bookmark(Bookmark),
29    File(File),
30    Image(Image),
31    CodeBlock(CodeBlock),
32    Katex(Katex),
33    Table(Table),
34    TableRow(TableRow),
35    TableCell(TableCell),
36}
37
38// Text # -------------------------------------------------- #
39#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
40pub struct Text {
41    /// Always "Text".
42    pub r#type: String,
43    /// Always `true`
44    pub inline: bool,
45
46    pub props: TextProps,
47    // Always `None`
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub slots: Option<TextSlots>,
50}
51
52#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
53pub struct TextProps {
54    pub text: String,
55
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub color: Option<String>,
58
59    #[serde(skip_serializing_if = "Option::is_none")]
60    pub background_color: Option<String>,
61
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub bold: Option<bool>,
64
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub italic: Option<bool>,
67
68    #[serde(skip_serializing_if = "Option::is_none")]
69    pub underline: Option<bool>,
70
71    #[serde(skip_serializing_if = "Option::is_none")]
72    pub strikethrough: Option<bool>,
73
74    #[serde(skip_serializing_if = "Option::is_none")]
75    pub katex: Option<bool>,
76
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub code: Option<bool>,
79
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub ruby: Option<String>,
82
83    #[serde(skip_serializing_if = "Option::is_none")]
84    pub href: Option<String>,
85
86    #[serde(skip_serializing_if = "Option::is_none")]
87    pub favicon: Option<String>,
88}
89
90#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
91pub struct TextSlots;
92
93// Icon # -------------------------------------------------- #
94#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
95pub struct Icon {
96    /// Always "Icon".
97    pub r#type: String,
98
99    /// Always `true`
100    pub inline: bool,
101
102    pub props: IconProps,
103
104    // Always `None`
105    #[serde(skip_serializing_if = "Option::is_none")]
106    pub slots: Option<IconSlots>,
107}
108
109#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
110pub struct IconProps {
111    pub src: String,
112
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub alt: Option<String>,
115}
116
117#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
118pub struct IconSlots;
119
120// Heading # -------------------------------------------------- #
121#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
122pub struct Heading {
123    /// Always "Heading".
124    pub r#type: String,
125
126    /// Always `false`
127    pub inline: bool,
128
129    pub props: HeadingProps,
130
131    pub slots: HeadingSlots,
132}
133
134#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
135#[serde(rename_all = "lowercase")]
136#[serde(try_from = "u8", into = "u8")]
137pub enum HeadingLevel {
138    #[default]
139    H1,
140    H2,
141    H3,
142    H4,
143    H5,
144    H6,
145}
146
147impl From<HeadingLevel> for u8 {
148    fn from(level: HeadingLevel) -> Self {
149        match level {
150            HeadingLevel::H1 => 1,
151            HeadingLevel::H2 => 2,
152            HeadingLevel::H3 => 3,
153            HeadingLevel::H4 => 4,
154            HeadingLevel::H5 => 5,
155            HeadingLevel::H6 => 6,
156        }
157    }
158}
159
160impl TryFrom<u8> for HeadingLevel {
161    type Error = String;
162
163    fn try_from(value: u8) -> Result<Self, Self::Error> {
164        match value {
165            1 => Ok(HeadingLevel::H1),
166            2 => Ok(HeadingLevel::H2),
167            3 => Ok(HeadingLevel::H3),
168            4 => Ok(HeadingLevel::H4),
169            5 => Ok(HeadingLevel::H5),
170            6 => Ok(HeadingLevel::H6),
171            _ => Err(format!("Invalid heading level: {}", value)),
172        }
173    }
174}
175
176#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
177pub struct HeadingProps {
178    pub level: HeadingLevel,
179}
180
181#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
182pub struct HeadingSlots {
183    pub default: Vec<InlineComponent>,
184}
185
186// Paragraph # -------------------------------------------------- #
187#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
188pub struct Paragraph {
189    /// Always "Paragraph".
190    pub r#type: String,
191
192    /// Always `false`
193    pub inline: bool,
194
195    // Always `None`
196    #[serde(skip_serializing_if = "Option::is_none")]
197    pub props: Option<ParagraphProps>,
198
199    pub slots: ParagraphSlots,
200}
201
202#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
203pub struct ParagraphProps;
204
205#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
206pub struct ParagraphSlots {
207    pub default: Vec<InlineComponent>,
208}
209
210// ListItem # -------------------------------------------------- #
211#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
212pub struct ListItem {
213    pub r#type: String,
214    pub inline: bool,
215    #[serde(skip_serializing_if = "Option::is_none")]
216    pub props: Option<ListItemProps>,
217    pub slots: ListItemSlots,
218}
219
220#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
221pub struct ListItemProps;
222
223#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
224pub struct ListItemSlots {
225    pub default: Vec<InlineComponent>,
226}
227
228// List # -------------------------------------------------- #
229#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
230pub struct List {
231    pub r#type: String,
232    pub inline: bool,
233    #[serde(skip_serializing_if = "Option::is_none")]
234    pub props: Option<ListProps>,
235    pub slots: ListSlots,
236}
237
238#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
239pub struct ListProps {
240    #[serde(skip_serializing_if = "Option::is_none")]
241    pub list_style: Option<ListStyle>,
242}
243
244#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
245#[serde(rename_all = "lowercase")]
246pub enum ListStyle {
247    #[default]
248    Unordered,
249    Ordered,
250}
251
252#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
253pub struct ListSlots {
254    pub default: Vec<ListItem>,
255}
256
257// BlockQuote # -------------------------------------------------- #
258#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
259pub struct BlockQuote {
260    pub r#type: String,
261    pub inline: bool,
262    #[serde(skip_serializing_if = "Option::is_none")]
263    pub props: Option<BlockQuoteProps>,
264    pub slots: BlockQuoteSlots,
265}
266
267#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
268pub struct BlockQuoteProps {
269    #[serde(skip_serializing_if = "Option::is_none")]
270    pub cite: Option<String>,
271}
272
273#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
274pub struct BlockQuoteSlots {
275    pub default: Vec<Component>,
276}
277
278// Callout # -------------------------------------------------- #
279#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
280pub struct Callout {
281    pub r#type: String,
282    pub inline: bool,
283    #[serde(skip_serializing_if = "Option::is_none")]
284    pub props: Option<CalloutProps>,
285    pub slots: CalloutSlots,
286}
287
288#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
289#[serde(rename_all = "lowercase")]
290pub enum CalloutType {
291    #[default]
292    Note,
293    Tip,
294    Important,
295    Warning,
296    Caution,
297}
298
299#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
300pub struct CalloutProps {
301    #[serde(skip_serializing_if = "Option::is_none")]
302    pub r#type: Option<CalloutType>,
303}
304
305#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
306pub struct CalloutSlots {
307    pub default: Vec<Component>,
308}
309
310// Divider # -------------------------------------------------- #
311#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
312pub struct Divider {
313    pub r#type: String,
314    pub inline: bool,
315    #[serde(skip_serializing_if = "Option::is_none")]
316    pub props: Option<DividerProps>,
317    #[serde(skip_serializing_if = "Option::is_none")]
318    pub slots: Option<DividerSlots>,
319}
320
321#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
322pub struct DividerProps;
323
324#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
325pub struct DividerSlots;
326
327// Toggle # -------------------------------------------------- #
328#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
329pub struct Toggle {
330    pub r#type: String,
331    pub inline: bool,
332    #[serde(skip_serializing_if = "Option::is_none")]
333    pub props: Option<ToggleProps>,
334    pub slots: ToggleSlots,
335}
336
337#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
338pub struct ToggleProps;
339
340#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
341pub struct ToggleSlots {
342    pub default: Vec<Component>,
343    pub summary: Vec<InlineComponent>,
344}
345
346// Bookmark # -------------------------------------------------- #
347#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
348pub struct Bookmark {
349    pub r#type: String,
350    pub inline: bool,
351    pub props: BookmarkProps,
352    #[serde(skip_serializing_if = "Option::is_none")]
353    pub slots: Option<BookmarkSlots>,
354}
355
356#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
357pub struct BookmarkProps {
358    pub url: String,
359    #[serde(skip_serializing_if = "Option::is_none")]
360    pub title: Option<String>,
361    #[serde(skip_serializing_if = "Option::is_none")]
362    pub description: Option<String>,
363    #[serde(skip_serializing_if = "Option::is_none")]
364    pub image: Option<String>,
365}
366
367#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
368pub struct BookmarkSlots;
369
370// File # -------------------------------------------------- #
371#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
372pub struct File {
373    pub r#type: String,
374    pub inline: bool,
375    pub props: FileProps,
376    #[serde(skip_serializing_if = "Option::is_none")]
377    pub slots: Option<FileSlots>,
378}
379
380#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
381pub struct FileProps {
382    pub src: String,
383    #[serde(skip_serializing_if = "Option::is_none")]
384    pub name: Option<String>,
385}
386
387#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
388pub struct FileSlots;
389
390// Image # -------------------------------------------------- #
391#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
392pub struct Image {
393    pub r#type: String,
394    pub inline: bool,
395    pub props: ImageProps,
396    #[serde(skip_serializing_if = "Option::is_none")]
397    pub slots: Option<ImageSlots>,
398}
399
400#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
401pub struct ImageProps {
402    pub src: String,
403    #[serde(skip_serializing_if = "Option::is_none")]
404    pub alt: Option<String>,
405}
406
407#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
408pub struct ImageSlots;
409
410// CodeBlock # -------------------------------------------------- #
411#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
412pub struct CodeBlock {
413    pub r#type: String,
414    pub inline: bool,
415    pub props: CodeBlockProps,
416    pub slots: CodeBlockSlots,
417}
418
419#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
420pub struct CodeBlockProps {
421    pub code: String,
422    pub language: String,
423}
424
425#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
426pub struct CodeBlockSlots {
427    pub default: Vec<InlineComponent>,
428}
429
430// Katex # -------------------------------------------------- #
431#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
432pub struct Katex {
433    pub r#type: String,
434    pub inline: bool,
435    pub props: KatexProps,
436    #[serde(skip_serializing_if = "Option::is_none")]
437    pub slots: Option<KatexSlots>,
438}
439
440#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
441pub struct KatexProps {
442    pub expression: String,
443}
444
445#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
446pub struct KatexSlots;
447
448// Table # -------------------------------------------------- #
449#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
450pub struct Table {
451    pub r#type: String,
452    pub inline: bool,
453    #[serde(skip_serializing_if = "Option::is_none")]
454    pub props: Option<TableProps>,
455    pub slots: TableSlots,
456}
457
458#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
459pub struct TableProps {
460    #[serde(skip_serializing_if = "Option::is_none")]
461    pub has_column_header: Option<bool>,
462    #[serde(skip_serializing_if = "Option::is_none")]
463    pub has_row_header: Option<bool>,
464    #[serde(skip_serializing_if = "Option::is_none")]
465    pub caption: Option<String>,
466}
467
468#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
469pub struct TableSlots {
470    #[serde(skip_serializing_if = "Option::is_none")]
471    pub header: Option<Vec<TableRow>>,
472    pub body: Vec<TableRow>,
473}
474
475// TableRow # -------------------------------------------------- #
476#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
477pub struct TableRow {
478    pub r#type: String,
479    pub inline: bool,
480    #[serde(skip_serializing_if = "Option::is_none")]
481    pub props: Option<TableRowProps>,
482    pub slots: TableRowSlots,
483}
484
485#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
486pub struct TableRowProps;
487
488#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
489pub struct TableRowSlots {
490    pub default: Vec<TableCell>,
491}
492
493// TableCell # -------------------------------------------------- #
494#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
495pub struct TableCell {
496    pub r#type: String,
497    pub inline: bool,
498    #[serde(skip_serializing_if = "Option::is_none")]
499    pub props: Option<TableCellProps>,
500    pub slots: TableCellSlots,
501}
502
503#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
504pub struct TableCellProps {
505    #[serde(skip_serializing_if = "Option::is_none")]
506    pub is_header: Option<bool>,
507}
508
509#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
510pub struct TableCellSlots {
511    pub default: Vec<InlineComponent>,
512}