use dioxus::prelude::*;
use dioxus_free_icons::{Icon, icons::ld_icons::*};
use crate::parser::{ExpandableNode, ResponseFieldNode};
#[derive(Props, Clone, PartialEq)]
pub struct DocResponseFieldProps {
pub field: ResponseFieldNode,
#[props(default = 0)]
pub depth: usize,
}
#[component]
pub fn DocResponseField(props: DocResponseFieldProps) -> Element {
let field = &props.field;
let description_html = if !field.content.is_empty() {
markdown::to_html_with_options(&field.content, &markdown::Options::gfm())
.unwrap_or_else(|_| field.content.clone())
} else {
String::new()
};
let indent_class = if props.depth > 0 {
"ml-4 border-l-2 border-base-300 pl-4"
} else {
""
};
rsx! {
div { class: "py-3 {indent_class}",
div { class: "flex items-start gap-2 flex-wrap",
code { class: "font-mono font-semibold text-base-content bg-base-300 px-2 py-0.5 rounded",
"{field.name}"
}
span { class: "badge badge-outline badge-sm",
"{field.field_type}"
}
if field.required {
span { class: "badge badge-success badge-sm",
"required"
}
}
}
if !description_html.is_empty() {
div {
class: "prose prose-sm max-w-none mt-2 text-base-content/80",
dangerous_inner_html: description_html,
}
}
if let Some(expandable) = &field.expandable {
DocExpandable {
expandable: expandable.clone(),
depth: props.depth + 1,
}
}
}
}
}
#[derive(Props, Clone, PartialEq)]
pub struct DocExpandableProps {
pub expandable: ExpandableNode,
#[props(default = 0)]
pub depth: usize,
}
#[component]
pub fn DocExpandable(props: DocExpandableProps) -> Element {
let mut expanded = use_signal(|| false);
let expandable = &props.expandable;
let chevron_class = if expanded() {
"size-4 text-base-content/50 transform rotate-90 transition-transform"
} else {
"size-4 text-base-content/50 transition-transform"
};
rsx! {
div { class: "mt-3 border border-base-300 rounded-lg overflow-hidden",
button {
class: "w-full flex items-center gap-2 px-3 py-2 text-left hover:bg-base-200 transition-colors text-sm",
onclick: move |_| expanded.set(!expanded()),
Icon { class: chevron_class, icon: LdChevronRight }
span { class: "font-medium text-base-content/70",
"{expandable.title}"
}
}
if expanded() {
div { class: "px-3 pb-3 border-t border-base-300 bg-base-200/30",
for (i, field) in expandable.fields.iter().enumerate() {
DocResponseField {
key: "{i}",
field: field.clone(),
depth: props.depth,
}
}
}
}
}
}
}