Fuma studio

API Page

This is the entry point and is responsible for rendering your api docs.

Installation

npx shadcn@latest add http://fumastudio/com/r/api-page.json
components/fumastudio/api-page.tsx
import { BaseURL } from "@/components/fumastudio/base-url";
import { DocsFooter } from "@/components/fumastudio/footer";
import { MockRequestProvider } from "@/components/fumastudio/mock-request";
import { Navigation } from "@/components/fumastudio/navigation";
import { PageContext } from "@/components/fumastudio/page-context";
import { SchemaProvider } from "@/components/fumastudio/schema";
import {
	AuthorizationScheme,
	PathParamsSchema,
	QueryParamsSchema,
	RequestBodySchema,
	ResponseBodySchema,
} from "@/components/fumastudio/scheme";
import {
	RequestSnippets,
	ResponseSnippets,
} from "@/components/fumastudio/snippet";
import { HttpCode, httpCodes } from "@/lib/http-codes";
import {
	type APIPageRequest,
	type loaderCtx,
	type Snippet,
} from "@trythis/nextjs";
import { getHttpCodes, normalizeServers } from "@trythis/nextjs/utils";

export type ApiPageProps = {
	request: APIPageRequest;
	requestSnippets: Snippet[];
	responseSnippets: Snippet[];
	schema: string | undefined;

	// Ctx provided as prop by collection loader
	loaderCtx: loaderCtx["loaderCtx"];
};

const APIPage = async ({
	request,
	requestSnippets,
	responseSnippets,
	schema = "",
	loaderCtx,
}: ApiPageProps) => {
	const authScheme = loaderCtx.auth;
	const serverScheme = loaderCtx.servers;
	const navigation = loaderCtx.navigation;
	const pageEntry = loaderCtx.pageEntry;
	const requestBodySchema = loaderCtx.requestBodySchema;
	const paramsQuerySchema = loaderCtx.paramsQuerySchema;
	const paramsPathSchema = loaderCtx.paramsPathSchema;
	const responseBodySchema = loaderCtx.responseBodySchema;
	const responseBodyMock = loaderCtx.responseBodyMock;

	const servers = normalizeServers(serverScheme);

	const httpStatusCodes = getHttpCodes(
		responseBodySchema,
		httpCodes as unknown as HttpCode[],
	);

	return (
		<MockRequestProvider
			proxyPath="/api/proxy"
			baseURL={request.url}
			intialRequests={[]}
			currentRequest={pageEntry}
			responseSnippets={responseSnippets}
			authSchemes={authScheme}
			servers={servers}
			defaultRequestBody={responseBodyMock}>
			<div className="w-full h-full">
				<header className="relative font-sans">
					<div className="mt-0.5 space-y-2.5">
						<div className="h-5 text-sm font-semibold text-primary dark:text-primary-light">
							{request.folder}
						</div>
						<div className="relative flex flex-col items-start gap-2 sm:flex-row sm:items-center">
							<h1 className="inline-block text-2xl font-bold tracking-tight text-gray-900 sm:text-3xl dark:text-gray-200">
								{request.name}
							</h1>
							<div className="items-center shrink-0 min-w-39 justify-end ml-auto sm:flex hidden">
								<PageContext schema={schema} />
							</div>
						</div>
					</div>
					<div className="mt-2 text-lg prose prose-gray dark:prose-invert">
						<p>{request.description}</p>
					</div>
				</header>

				<BaseURL url={request.url} method={request.method} />

				<div className="flex flex-col bg-accent border-input border gap-0 mt-6 px-1.5 pb-1.5 rounded-xl">
					<RequestSnippets snippets={requestSnippets} />
				</div>

				<div className="flex flex-col bg-accent border-input border gap-0 mt-6 px-1.5 pb-1.5 rounded-xl">
					<ResponseSnippets snippets={responseSnippets} />
				</div>

				<SchemaProvider>
					{authScheme && authScheme.length > 0 && (
						<div className="mt-8 font-sans">
							<AuthorizationScheme
								schema={authScheme}
							/>
						</div>
					)}

					{paramsQuerySchema && (
						<div className="mt-6 font-sans">
							<QueryParamsSchema
								schema={paramsQuerySchema}
							/>
						</div>
					)}

					{paramsPathSchema && (
						<div className="mt-6 font-sans">
							<PathParamsSchema
								schema={paramsPathSchema}
							/>
						</div>
					)}

					{requestBodySchema && (
						<div className="mt-6 font-sans">
							<RequestBodySchema
								schema={requestBodySchema}
							/>
						</div>
					)}

					{httpCodes && responseBodySchema && (
						<div className="mt-6 font-sans">
							<ResponseBodySchema
								httpCodes={httpStatusCodes}
								schema={responseBodySchema}
							/>
						</div>
					)}
				</SchemaProvider>

				{navigation && (
					<Navigation
						previous={navigation.previous}
						next={navigation.next}
					/>
				)}

				<DocsFooter />
			</div>
		</MockRequestProvider>
	);
};

export { APIPage };

Usage

mdx-components.tsx
import { APIPage } from "@/components/fumastudio/api-page";
import * as AllLucideIcons from "lucide-react";

type MDXComponents = any;

export const useIcons = (): any => {
	return AllLucideIcons;
};

const components: MDXComponents = {
	ApiPage: APIPage,
};

// Override or add your mdx components here
export function useMDXComponents(
	defaultComponents?: MDXComponents,
): MDXComponents {
	return {
		...defaultComponents,
		...components,
	};
}

Props