fml 0.4.0

Friendly Markup Language
Documentation
use dioxus::prelude::*;

use crate::ast::{Content, FmlCodeBlockValue, FmlValue, Section};

impl From<Content> for Element {
	fn from(content: Content) -> Self {
		rsx! {
			article {
				for section in content.0 {
					{Self::from(section)}
				}
			}
		}
	}
}

impl From<Section> for Element {
	fn from(section: Section) -> Self {
		rsx! {
			p {
				for fml in section.0 {
					{Self::from(fml)}
				}
			}
		}
	}
}

impl From<FmlValue> for Element {
	fn from(value: FmlValue) -> Self {
		match value {
			FmlValue::Linebreak => rsx! {
				br {}
			},
			FmlValue::Heading1(values) => rsx! {
				h1 {
					for v in values {
						{Self::from(v)}
					}
				}
			},
			FmlValue::Heading2(values) => rsx! {
				h2 {
					for v in values {
						{Self::from(v)}
					}
				}
			},
			FmlValue::Heading3(values) => rsx! {
				h3 {
					for v in values {
						{Self::from(v)}
					}
				}
			},
			FmlValue::Superline(values) => rsx! {
				sup { style: "display:block",
					for v in values {
						{Self::from(v)}
					}
				}
			},
			FmlValue::Subline(values) => rsx! {
				sub { style: "display:block",
					for v in values {
						{Self::from(v)}
					}
				}
			},
			FmlValue::Bold(values) => rsx! {
				strong {
					for v in values {
						{Self::from(v)}
					}
				}
			},
			FmlValue::Italic(values) => rsx! {
				i {
					for v in values {
						{Self::from(v)}
					}
				}
			},
			FmlValue::Strikethrough(values) => rsx! {
				s {
					for v in values {
						{Self::from(v)}
					}
				}
			},
			FmlValue::Quote(values) => rsx! {
				blockquote {
					for v in values {
						{Self::from(v)}
					}
				}
			},
			FmlValue::ListItem(values) => rsx! {
				// wrapping every li with ul to allow nesting
				ul {
					li {
						for v in values {
							{Self::from(v)}
						}
					}
				}
			},
			// Plaintext print of an unknown function
			FmlValue::Function(function) => {
				let mut lead = String::from("#");
				lead.push_str(&function.name);
				if let Some(params) = &function.params {
					lead.push('<');
					lead.push_str(params);
					lead.push('>');
				}
				lead.push('{');

				rsx! {
					"{lead}"
					for v in function.body {
						{Self::from(v)}
					}
					"}}"
				}
			}
			FmlValue::Superscript(values) => rsx! {
				sup {
					for v in values {
						{Self::from(v)}
					}
				}
			},
			FmlValue::Subscript(values) => rsx! {
				sub {
					for v in values {
						{Self::from(v)}
					}
				}
			},
			FmlValue::Underline(values) => rsx! {
				span { style: "text-decoration-line: underline;",
					for v in values {
						{Self::from(v)}
					}
				}
			},
			FmlValue::ColorFg(fml_color) => {
				let color = fml_color.color;
				rsx! {
					span { style: "color: {color};",
						for v in fml_color.body {
							{Self::from(v)}
						}
					}
				}
			}
			FmlValue::ColorBg(fml_color) => {
				let color = fml_color.color;
				rsx! {
					span { style: "background-color: {color};",
						for v in fml_color.body {
							{Self::from(v)}
						}
					}
				}
			}
			FmlValue::ContentWarning { reason, body } => rsx! {
				details {
					summary { "{reason}" }
					for v in body {
						{Self::from(v)}
					}
				}
			},
			FmlValue::CodeBlock { lang, body } => rsx! {
				pre {
					code { class: if let Some(lang) = lang { format!("language-{lang}") } else { "" },
						for v in body {
							{Self::from(v)}
						}
					}
				}
			},
			FmlValue::Hyperlink { fml, uri } => rsx! {
				a { href: uri,
					for v in fml {
						{Self::from(v)}
					}
				}
			},
			FmlValue::CodeInline(txt) => rsx! {
				code { "{txt}" }
			},
			FmlValue::Typst(typst) => rsx! { "{typst}" },
			FmlValue::Text(txt) => rsx! { "{txt}" },
		}
	}
}

impl From<FmlCodeBlockValue> for Element {
	fn from(value: FmlCodeBlockValue) -> Self {
		match value {
			FmlCodeBlockValue::Str(txt) => rsx! { "{txt}" },
			FmlCodeBlockValue::Linebreak => rsx! {
				br {}
			},
		}
	}
}