dioxus_mdx/components/openapi/
endpoint_page.rs1use dioxus::prelude::*;
4
5use crate::parser::{ApiOperation, OpenApiSpec, highlight_code};
6
7use super::method_badge::MethodBadge;
8use super::parameters_list::ParametersList;
9use super::request_body::RequestBodySection;
10use super::responses_list::ResponsesList;
11
12#[derive(Props, Clone, PartialEq)]
14pub struct EndpointPageProps {
15 pub operation: ApiOperation,
17 pub spec: OpenApiSpec,
19}
20
21#[component]
26pub fn EndpointPage(props: EndpointPageProps) -> Element {
27 let op = &props.operation;
28 let spec = &props.spec;
29
30 let base_url = spec
31 .servers
32 .first()
33 .map(|s| s.url.as_str())
34 .unwrap_or("https://api.example.com");
35
36 let curl = op.generate_curl(base_url);
37 let curl_highlighted = highlight_code(&curl, Some("bash"));
38
39 let response_example = op.generate_response_example();
40
41 let method_bg = op.method.bg_class();
42
43 rsx! {
44 div { class: "flex flex-col lg:flex-row gap-0",
45 div { class: "flex-1 min-w-0 px-8 py-12 lg:px-12",
47 div { class: "max-w-2xl",
48 div { class: "flex items-center gap-3 mb-6",
50 span {
51 class: "px-3 py-1.5 rounded-lg font-mono text-sm font-bold border {method_bg}",
52 "{op.method.as_str()}"
53 }
54 code { class: "font-mono text-lg text-base-content",
55 "{op.path}"
56 }
57 if op.deprecated {
58 span { class: "badge badge-warning badge-sm", "deprecated" }
59 }
60 }
61
62 if let Some(summary) = &op.summary {
64 h1 { class: "text-3xl font-bold tracking-tight mb-3",
65 "{summary}"
66 }
67 }
68
69 if let Some(desc) = &op.description {
71 p { class: "text-base text-base-content/70 mb-6 leading-relaxed",
72 "{desc}"
73 }
74 }
75
76 div { class: "mb-8 flex items-center gap-2",
78 span { class: "text-xs text-base-content/50 font-semibold uppercase tracking-wider",
79 "Base URL"
80 }
81 code { class: "text-sm font-mono text-base-content/70 bg-base-200 px-2 py-1 rounded",
82 "{base_url}"
83 }
84 }
85
86 if !op.parameters.is_empty() {
88 div { class: "mb-8",
89 h2 { class: "text-lg font-semibold mb-4 pb-2 border-b border-base-300",
90 "Parameters"
91 }
92 ParametersList { parameters: op.parameters.clone() }
93 }
94 }
95
96 if let Some(body) = &op.request_body {
98 div { class: "mb-8",
99 h2 { class: "text-lg font-semibold mb-4 pb-2 border-b border-base-300",
100 "Request Body"
101 }
102 RequestBodySection { body: body.clone() }
103 }
104 }
105
106 if !op.responses.is_empty() {
108 div { class: "mb-8",
109 h2 { class: "text-lg font-semibold mb-4 pb-2 border-b border-base-300",
110 "Responses"
111 }
112 ResponsesList { responses: op.responses.clone() }
113 }
114 }
115 }
116 }
117
118 aside { class: "lg:w-[45%] lg:shrink-0 lg:border-l border-base-300 bg-base-200/20",
120 div { class: "lg:sticky lg:top-16 lg:h-[calc(100vh-4rem)] lg:overflow-y-auto p-6 space-y-6",
121 div {
123 h3 { class: "text-sm font-semibold text-base-content/70 uppercase tracking-wider mb-3",
124 "Request"
125 }
126 div { class: "rounded-lg border border-base-300 overflow-hidden",
127 div { class: "px-3 py-2 bg-base-300/50 border-b border-base-300 flex items-center gap-2",
128 MethodBadge { method: op.method }
129 code { class: "text-xs font-mono text-base-content/70 truncate",
130 "{op.path}"
131 }
132 }
133 pre { class: "bg-base-300/30 p-4 overflow-x-auto syntax-highlight",
134 code {
135 class: "text-sm font-mono leading-relaxed",
136 dangerous_inner_html: "{curl_highlighted}",
137 }
138 }
139 }
140 }
141
142 if let Some((status_code, response_json)) = &response_example {
144 {
145 let json_highlighted = highlight_code(response_json, Some("json"));
146 let status_color = if status_code.starts_with('2') {
147 "badge-success"
148 } else if status_code.starts_with('3') {
149 "badge-info"
150 } else {
151 "badge-ghost"
152 };
153 rsx! {
154 div {
155 h3 { class: "text-sm font-semibold text-base-content/70 uppercase tracking-wider mb-3",
156 "Response"
157 }
158 div { class: "rounded-lg border border-base-300 overflow-hidden",
159 div { class: "px-3 py-2 bg-base-300/50 border-b border-base-300 flex items-center gap-2",
160 span { class: "badge {status_color} badge-sm font-mono font-bold",
161 "{status_code}"
162 }
163 span { class: "text-xs text-base-content/50",
164 "application/json"
165 }
166 }
167 pre { class: "bg-base-300/30 p-4 overflow-x-auto syntax-highlight max-h-[60vh]",
168 code {
169 class: "text-sm font-mono leading-relaxed",
170 dangerous_inner_html: "{json_highlighted}",
171 }
172 }
173 }
174 }
175 }
176 }
177 }
178 }
179 }
180 }
181 }
182}