docs: fix APIMethod component styling after fumadocs update (#4421)

This commit is contained in:
KinfeMichael Tariku
2025-09-04 22:10:46 +03:00
committed by GitHub
parent c29fabe0dc
commit 6a7f50162e
4 changed files with 126 additions and 22 deletions

View File

@@ -1,6 +1,6 @@
import { Endpoint } from "./endpoint";
// import { Tab, Tabs } from "fumadocs-ui/components/tabs";
import { DynamicCodeBlock } from "fumadocs-ui/components/dynamic-codeblock";
import { DynamicCodeBlock } from "./ui/dynamic-code-block";
import {
Table,
TableBody,

View File

@@ -33,26 +33,6 @@ export function Endpoint({
>
<Method method={method} />
<span className="font-mono text-sm text-muted-foreground">{path}</span>
<div className="absolute right-2" slot="copy">
<Button
variant="ghost"
size="icon"
className="transition-all duration-150 ease-in-out opacity-0 cursor-pointer scale-80 group-hover:opacity-100"
onClick={() => {
setCopying(true);
navigator.clipboard.writeText(path);
setTimeout(() => {
setCopying(false);
}, 1000);
}}
>
{copying ? (
<Check className="duration-150 ease-in-out size-4 zoom-in" />
) : (
<Copy className="size-4" />
)}
</Button>
</div>
</div>
);
}

View File

@@ -183,7 +183,7 @@ function CopyButton({
variant: "ghost",
size: "icon",
}),
"transition-opacity border-none group-hover:opacity-100",
"transition-opacity size-7 border-none group-hover:opacity-100",
"opacity-0 group-hover:opacity-100",
"group-hover:opacity-100",
className,

View File

@@ -0,0 +1,124 @@
"use client";
import {
CodeBlock,
type CodeBlockProps,
Pre,
} from "@/components/ui/code-block";
import type {
HighlightOptions,
HighlightOptionsCommon,
HighlightOptionsThemes,
} from "fumadocs-core/highlight";
import { useShiki } from "fumadocs-core/highlight/client";
import { cn } from "@/lib/utils";
import {
type ComponentProps,
createContext,
type FC,
Suspense,
use,
} from "react";
export interface DynamicCodeblockProps {
lang: string;
code: string;
/**
* Extra props for the underlying `<CodeBlock />` component.
*
* Ignored if you defined your own `pre` component in `options.components`.
*/
codeblock?: CodeBlockProps;
/**
* Wrap in React `<Suspense />` and provide a fallback.
*
* @defaultValue true
*/
wrapInSuspense?: boolean;
options?: Omit<HighlightOptionsCommon, "lang"> & HighlightOptionsThemes;
}
const PropsContext = createContext<CodeBlockProps | undefined>(undefined);
function DefaultPre(props: ComponentProps<"pre">) {
const extraProps = use(PropsContext);
return (
<CodeBlock
{...props}
{...extraProps}
className={cn(
"my-0 border-t-0 rounded-none",
props.className,
extraProps?.className,
)}
>
<Pre className="py-2">{props.children}</Pre>
</CodeBlock>
);
}
export function DynamicCodeBlock({
lang,
code,
codeblock,
options,
wrapInSuspense = true,
}: DynamicCodeblockProps) {
const shikiOptions = {
lang,
...options,
components: {
pre: DefaultPre,
...options?.components,
},
} satisfies HighlightOptions;
let children = <Internal code={code} options={shikiOptions} />;
if (wrapInSuspense)
children = (
<Suspense
fallback={
<Placeholder code={code} components={shikiOptions.components} />
}
>
{children}
</Suspense>
);
return <PropsContext value={codeblock}>{children}</PropsContext>;
}
function Placeholder({
code,
components = {},
}: {
code: string;
components: HighlightOptions["components"];
}) {
const { pre: Pre = "pre", code: Code = "code" } = components as Record<
string,
FC
>;
return (
<Pre>
<Code>
{code.split("\n").map((line, i) => (
<span key={i} className="line">
{line}
</span>
))}
</Code>
</Pre>
);
}
function Internal({
code,
options,
}: {
code: string;
options: HighlightOptions;
}) {
return useShiki(code, options);
}