Skip to main content

dioxus_mdx/components/
callout.rs

1//! Callout component for Tip, Note, Warning, and Info boxes.
2
3use dioxus::prelude::*;
4use dioxus_free_icons::{Icon, icons::ld_icons::*};
5
6use crate::parser::CalloutType;
7
8/// Props for DocCallout component.
9#[derive(Props, Clone, PartialEq)]
10pub struct DocCalloutProps {
11    /// Type of callout (Tip, Note, Warning, Info).
12    pub callout_type: CalloutType,
13    /// Content to display (rendered as markdown).
14    pub content: String,
15}
16
17/// Callout box component styled with DaisyUI alerts.
18#[component]
19pub fn DocCallout(props: DocCalloutProps) -> Element {
20    let (bg_class, border_class, icon_class, shadow_class) = match props.callout_type {
21        CalloutType::Tip => (
22            "bg-success/5",
23            "border-success/40",
24            "text-success",
25            "shadow-success/5",
26        ),
27        CalloutType::Note => ("bg-info/5", "border-info/40", "text-info", "shadow-info/5"),
28        CalloutType::Warning => (
29            "bg-warning/5",
30            "border-warning/40",
31            "text-warning",
32            "shadow-warning/5",
33        ),
34        CalloutType::Info => ("bg-info/5", "border-info/40", "text-info", "shadow-info/5"),
35    };
36
37    // Render markdown content
38    let html = markdown::to_html_with_options(&props.content, &markdown::Options::gfm())
39        .unwrap_or_else(|_| props.content.clone());
40
41    rsx! {
42        div {
43            class: "my-6 px-4 py-4 rounded-lg border-l-4 {bg_class} {border_class} shadow-sm {shadow_class}",
44            role: "alert",
45            div { class: "flex gap-4",
46                // Icon - slightly larger
47                div { class: "{icon_class} mt-0.5 shrink-0",
48                    match props.callout_type {
49                        CalloutType::Tip => rsx! { Icon { class: "size-5", icon: LdLightbulb } },
50                        CalloutType::Note => rsx! { Icon { class: "size-5", icon: LdInfo } },
51                        CalloutType::Warning => rsx! { Icon { class: "size-5", icon: LdTriangleAlert } },
52                        CalloutType::Info => rsx! { Icon { class: "size-5", icon: LdInfo } },
53                    }
54                }
55                // Content
56                div { class: "flex-1 min-w-0",
57                    // Label - inline with better weight
58                    span { class: "font-semibold {icon_class} text-sm uppercase tracking-wide",
59                        "{props.callout_type.as_str()}"
60                    }
61                    // Content (markdown rendered) - better spacing
62                    div {
63                        class: "prose prose-sm max-w-none text-base-content/85 mt-1.5 [&>p:first-child]:mt-0 [&>p:last-child]:mb-0",
64                        dangerous_inner_html: html,
65                    }
66                }
67            }
68        }
69    }
70}