ewdlop's picture
App.tsx
42ae0b9
Raw
History Blame Contribute Delete
3.13 kB
import { useEffect, useRef, useState } from "react";
import { Link } from "wouter";
import { ArrowLeft, Loader2 } from "lucide-react";
// @ts-expect-error no types
import SwaggerUIBundle from "swagger-ui-dist/swagger-ui-bundle.js";
import "swagger-ui-dist/swagger-ui.css";
export default function SwaggerPage() {
const containerRef = useRef<HTMLDivElement>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
if (!containerRef.current) return;
// Determine the OpenAPI JSON URL — same origin as the page
const base = (import.meta.env.VITE_API_BASE as string | undefined) ?? "";
const url = `${base}/openapi.json`;
try {
SwaggerUIBundle({
url,
domNode: containerRef.current,
presets: [SwaggerUIBundle.presets.apis, SwaggerUIBundle.SwaggerUIStandalonePreset],
layout: "BaseLayout",
deepLinking: true,
displayRequestDuration: true,
filter: true,
tryItOutEnabled: true,
onComplete: () => setLoading(false),
});
setLoading(false);
} catch (e) {
setError(String(e));
setLoading(false);
}
}, []);
return (
<div className="flex flex-col h-screen" style={{ background: "var(--bg-base)", color: "var(--text-primary)" }}>
{/* Header */}
<header
className="flex items-center gap-3 px-4 py-2.5 flex-shrink-0"
style={{ borderBottom: "1px solid var(--border)", background: "var(--bg-surface)" }}
>
<Link href="/">
<button
className="flex items-center gap-1.5 h-7 px-2 text-xs rounded transition-colors"
style={{ color: "var(--text-secondary)" }}
onMouseEnter={(e) => (e.currentTarget.style.color = "var(--text-primary)")}
onMouseLeave={(e) => (e.currentTarget.style.color = "var(--text-secondary)")}
>
<ArrowLeft size={12} />
Back to Analyzer
</button>
</Link>
<span className="text-sm font-semibold">API Documentation</span>
<span
className="text-[10px] px-1.5 py-0.5 rounded"
style={{
background: "rgba(88,166,255,0.12)",
color: "var(--accent-blue)",
border: "1px solid rgba(88,166,255,0.25)",
fontFamily: "var(--font-mono)",
}}
>
OpenAPI 3.1
</span>
</header>
{/* Swagger UI */}
<div className="flex-1 overflow-auto" style={{ background: "#fff" }}>
{loading && (
<div className="flex items-center justify-center h-full gap-2" style={{ color: "#666" }}>
<Loader2 size={16} className="animate-spin" />
<span className="text-sm">Loading API docs…</span>
</div>
)}
{error && (
<div className="flex items-center justify-center h-full">
<p className="text-sm text-red-600">Failed to load API docs: {error}</p>
</div>
)}
<div ref={containerRef} className={loading ? "hidden" : ""} />
</div>
</div>
);
}