use super::*;
#[component]
pub fn euv_markdown(node: VirtualNode<EuvMarkdownProps>) -> VirtualNode {
let EuvMarkdownProps { blocks }: EuvMarkdownProps = node.try_get_props().unwrap_or_default();
let content: VirtualNode = euv_markdown_blocks(blocks);
html! {
article {
class: c_euv_markdown()
class: "md-body"
content
}
}
}
pub fn euv_markdown_blocks(blocks: &'static [EuvMdBlock]) -> VirtualNode {
html! {
for block in blocks.iter() {
{ render_md_block(block) }
}
}
}
fn render_md_block(block: &'static EuvMdBlock) -> VirtualNode {
match block {
EuvMdBlock::Heading {
level,
id,
href,
inline,
} => render_md_heading(*level, id, href, inline),
EuvMdBlock::Paragraph(inline) => {
let content: VirtualNode = render_md_inlines(inline);
html! {
p {
content
}
}
}
EuvMdBlock::CodeBlock { lang, code } => html! {
pre {
class: format!("language-{lang}")
code {
{ *code }
}
}
},
EuvMdBlock::BlockQuote(blocks) => {
let content: VirtualNode = euv_markdown_blocks(blocks);
html! {
blockquote {
content
}
}
}
EuvMdBlock::List { ordered, items } => {
if *ordered {
html! {
ol {
for item in items.iter() {
li {
{ euv_markdown_blocks(item) }
}
}
}
}
} else {
html! {
ul {
for item in items.iter() {
li {
{ euv_markdown_blocks(item) }
}
}
}
}
}
}
EuvMdBlock::Table { head, rows } => html! {
table {
thead {
tr {
for cell in head.iter() {
th {
{ render_md_inlines(cell) }
}
}
}
}
tbody {
for row in rows.iter() {
tr {
for cell in row.iter() {
td {
{ render_md_inlines(cell) }
}
}
}
}
}
}
},
EuvMdBlock::Container {
kind,
title,
blocks,
} => {
let content: VirtualNode = euv_markdown_blocks(blocks);
html! {
div {
class: format!("docs-container {kind}")
p {
class: "docs-container-title"
{ *title }
}
content
}
}
}
EuvMdBlock::Rule => html! {
hr {}
},
EuvMdBlock::Html(raw) => html! {
div {
inner_html: *raw
}
},
}
}
fn render_md_heading(
level: u8,
id: &'static str,
href: &'static str,
inline: &'static [EuvMdInline],
) -> VirtualNode {
let anchor: VirtualNode = html! {
a {
class: "header-anchor"
href: href
span { "#" }
}
};
let content: VirtualNode = render_md_inlines(inline);
match level {
1 => html! {
h1 {
id: id
anchor
content
}
},
2 => html! {
h2 {
id: id
anchor
content
}
},
3 => html! {
h3 {
id: id
anchor
content
}
},
4 => html! {
h4 {
id: id
anchor
content
}
},
5 => html! {
h5 {
id: id
anchor
content
}
},
_ => html! {
h6 {
id: id
anchor
content
}
},
}
}
fn render_md_inlines(inlines: &'static [EuvMdInline]) -> VirtualNode {
html! {
for inline in inlines.iter() {
{ render_md_inline(inline) }
}
}
}
fn render_md_inline(inline: &'static EuvMdInline) -> VirtualNode {
match inline {
EuvMdInline::Text(text) => html! {
{ *text }
},
EuvMdInline::Strong(children) => {
let content: VirtualNode = render_md_inlines(children);
html! {
strong {
content
}
}
}
EuvMdInline::Em(children) => {
let content: VirtualNode = render_md_inlines(children);
html! {
em {
content
}
}
}
EuvMdInline::Del(children) => {
let content: VirtualNode = render_md_inlines(children);
html! {
del {
content
}
}
}
EuvMdInline::Code(code) => html! {
code {
{ *code }
}
},
EuvMdInline::Link {
href,
external,
children,
} => {
let content: VirtualNode = render_md_inlines(children);
if *external {
html! {
a {
href: *href
target: "_blank"
content
}
}
} else {
html! {
a {
href: *href
content
}
}
}
}
EuvMdInline::Image { src, alt } => html! {
img {
src: *src
alt: *alt
}
},
EuvMdInline::TaskMarker(checked) => {
if *checked {
html! {
span {
class: "task-marker"
"☑"
}
}
} else {
html! {
span {
class: "task-marker"
"☐"
}
}
}
}
EuvMdInline::SoftBreak => html! {
" "
},
EuvMdInline::HardBreak => html! {
br {}
},
EuvMdInline::Html(raw) => html! {
span {
inner_html: *raw
}
},
}
}