Fuma studio

Config Provider

Installation

npx shadcn@latest add http://fumastudio/com/r/config-provider.json
components/fumastudio/config-provider.tsx
"use client";

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { createContext, type ReactNode, useContext } from "react";

const queryClient = new QueryClient();

export type Socials = {
	href: string;
	label: string;
	iconUrl: string;
};

export interface CopyPageDropdown {
	id: string;
	label: string;
	description: string;
	url?: string;
	icon?: React.ReactNode;
}

type CopyPageOptions = {
	enabled: boolean;
	enableDropdown?: boolean;
	dropdown?: CopyPageDropdown[];
};

export type Settings = {
	enableTryItButton?: boolean;
	poweredBy?: ReactNode | null;
	socials?: Socials[];
	copyPage?: CopyPageOptions;
};

const ConfigContext = createContext<Settings | null>(null);

const defaultConfig: Settings = {
	enableTryItButton: false,
	poweredBy: null,
	socials: [],
	copyPage: {
		enabled: true,
		enableDropdown: true,
		dropdown: [],
	},
};

export function ConfigProvider(props: {
	children: ReactNode;
	config: Settings | null;
}) {
	return (
		<ConfigContext.Provider
			value={props.config ? props.config : defaultConfig}>
			{props.children}
		</ConfigContext.Provider>
	);
}

export const useConfig = () => {
	const ctx = useContext(ConfigContext);
	if (!ctx)
		throw new Error(
			"useSettings must be used inside <SettingsProvider />",
		);
	return ctx;
};

export function TanstackProvider(props: { children: React.ReactNode }) {
	return (
		<QueryClientProvider client={queryClient}>
			{props.children}
		</QueryClientProvider>
	);
}

Usage

app/layout.tsx
import { TanstackProvider } from "@/components/fumastudio/config-provider";

export default function Layout({ children }: { children: ReactNode }) {
	return (
		<html
			lang="en"
			className="antialiased"
			suppressHydrationWarning>
			<body className="min-h-screen ">
				<TanstackProvider>
					{children}
					<Toaster />
				</TanstackProvider>
			</body>
		</html>
	);
}

Usage

app/api-reference/[[...slug]]/page.tsx
import { source } from "@/lib/source";
import { useMDXComponents } from "@/mdx-components";
import { ConfigProvider } from "@/components/fumastudio/config-provider";

type PageParams = { slug: string[] };

type PageProps = {
	params: Promise<PageParams>;
};

export default async function Page(props: PageProps) {
	const params = await props.params;
	const src = await source.getPage(params.slug);

	if (!src) {
		return notFound();
	}

	const MDX = src.data.body;
	const pageTree = source.getPageTree();

	const schemes = await source.getSchemes(params.slug);

	return (
		<SidebarProvider>
			<PageTree tree={pageTree} />

			<SidebarInset>
				<div className="flex items-center h-14 gap-2 px-4 border-b shrink-0">
					<div className="flex items-center">
						<SidebarTrigger className="ml-1.5" />
						<Separator
							orientation="vertical"
							className="mr-2 data-[orientation=vertical]:h-4"
						/>
					</div>

					<div className="flex items-center ml-auto">
						<SearchDialog />
						<ThemeSelector />
					</div>
				</div>

				<ConfigProvider config={config}>
					<div className="flex flex-col flex-1 gap-4 pt-24 mx-auto w-full max-w-[70rem] px-16 md:max-w-[60rem] md:px-24 group is-api-page">
						<MDX
							schemes={schemes}
							components={useMDXComponents()}
						/>
					</div>
				</ConfigProvider>
			</SidebarInset>
		</SidebarProvider>
	);
}

Props