use dioxus::prelude::*;
#[cfg(feature = "highlight")]
use dioxus_code::{Code, CodeTheme, Language, SourceCode, Theme};
use crate::parser::{ApiOperation, OpenApiSpec};
use super::method_badge::MethodBadge;
use super::parameters_list::ParametersList;
use super::request_body::RequestBodySection;
use super::responses_list::ResponsesList;
enum SampleLang {
Bash,
Json,
}
#[cfg(feature = "highlight")]
fn code_sample(code: String, lang: SampleLang) -> Element {
let language = match lang {
SampleLang::Bash => Language::Bash,
SampleLang::Json => Language::Json,
};
let theme = CodeTheme::system(Theme::GITHUB_LIGHT, Theme::TOKYO_NIGHT);
rsx! {
Code {
src: SourceCode::new(language, code),
theme,
}
}
}
#[cfg(not(feature = "highlight"))]
fn code_sample(code: String, _lang: SampleLang) -> Element {
crate::components::code::plain_code_block(&code)
}
#[derive(Props, Clone, PartialEq)]
pub struct EndpointPageProps {
pub operation: ApiOperation,
pub spec: OpenApiSpec,
}
#[component]
pub fn EndpointPage(props: EndpointPageProps) -> Element {
let op = &props.operation;
let spec = &props.spec;
let base_url = spec
.servers
.first()
.map(|s| s.url.as_str())
.unwrap_or("https://api.example.com");
let curl = op.generate_curl(base_url);
let response_example = op.generate_response_example();
let method_bg = op.method.bg_class();
rsx! {
div { class: "flex flex-col lg:flex-row gap-0",
div { class: "flex-1 min-w-0 px-8 py-12 lg:px-12",
div { class: "max-w-2xl",
div { class: "flex items-center gap-3 mb-6",
span {
class: "px-3 py-1.5 rounded-lg font-mono text-sm font-bold border {method_bg}",
"{op.method.as_str()}"
}
code { class: "font-mono text-lg text-base-content",
"{op.path}"
}
if op.deprecated {
span { class: "badge badge-warning badge-sm", "deprecated" }
}
}
if let Some(summary) = &op.summary {
h1 { class: "text-3xl font-bold tracking-tight mb-3",
"{summary}"
}
}
if let Some(desc) = &op.description {
p { class: "text-base text-base-content/70 mb-6 leading-relaxed",
"{desc}"
}
}
div { class: "mb-8 flex items-center gap-2",
span { class: "text-xs text-base-content/50 font-semibold uppercase tracking-wider",
"Base URL"
}
code { class: "text-sm font-mono text-base-content/70 bg-base-200 px-2 py-1 rounded",
"{base_url}"
}
}
if !op.parameters.is_empty() {
div { class: "mb-8",
h2 { class: "text-lg font-semibold mb-4 pb-2 border-b border-base-300",
"Parameters"
}
ParametersList { parameters: op.parameters.clone() }
}
}
if let Some(body) = &op.request_body {
div { class: "mb-8",
h2 { class: "text-lg font-semibold mb-4 pb-2 border-b border-base-300",
"Request Body"
}
RequestBodySection { body: body.clone() }
}
}
if !op.responses.is_empty() {
div { class: "mb-8",
h2 { class: "text-lg font-semibold mb-4 pb-2 border-b border-base-300",
"Responses"
}
ResponsesList { responses: op.responses.clone() }
}
}
}
}
aside { class: "lg:w-[45%] lg:shrink-0 lg:border-l border-base-300 bg-base-200/20",
div { class: "lg:sticky lg:top-16 lg:h-[calc(100vh-4rem)] lg:overflow-y-auto p-6 space-y-6",
div {
h3 { class: "text-sm font-semibold text-base-content/70 uppercase tracking-wider mb-3",
"Request"
}
div { class: "rounded-lg border border-base-300 overflow-hidden",
div { class: "px-3 py-2 bg-base-300/50 border-b border-base-300 flex items-center gap-2",
MethodBadge { method: op.method }
code { class: "text-xs font-mono text-base-content/70 truncate",
"{op.path}"
}
}
div { class: "dk-code-block-body bg-base-200",
{code_sample(curl.clone(), SampleLang::Bash)}
}
}
}
if let Some((status_code, response_json)) = &response_example {
{
let status_color = if status_code.starts_with('2') {
"badge-success"
} else if status_code.starts_with('3') {
"badge-info"
} else {
"badge-ghost"
};
rsx! {
div {
h3 { class: "text-sm font-semibold text-base-content/70 uppercase tracking-wider mb-3",
"Response"
}
div { class: "rounded-lg border border-base-300 overflow-hidden",
div { class: "px-3 py-2 bg-base-300/50 border-b border-base-300 flex items-center gap-2",
span { class: "badge {status_color} badge-sm font-mono font-bold",
"{status_code}"
}
span { class: "text-xs text-base-content/50",
"application/json"
}
}
div { class: "dk-code-block-body bg-base-200 max-h-[60vh] overflow-y-auto",
{code_sample(response_json.clone(), SampleLang::Json)}
}
}
}
}
}
}
}
}
}
}
}