mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-07 07:55:13 +02:00
fix(docs): replace broken page copy buttons with working single button
The three page-level buttons (Copy MD, View MD, Copy MDX) were broken because the fetch URL missed the /ktx basePath. Replace with a single "Copy as Markdown" button that strips frontmatter from the MDX source already available client-side — no fetch needed. Drop the .md link since agents discover markdown URLs through llms.txt and content negotiation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e64da5a85d
commit
63e2773e0a
2 changed files with 25 additions and 100 deletions
|
|
@ -51,10 +51,7 @@ export default async function Page(props: {
|
|||
<>
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between sm:gap-4">
|
||||
<DocsTitle>{page.data.title}</DocsTitle>
|
||||
<DocsPageActions
|
||||
markdownUrl={`${page.url}.md`}
|
||||
mdxSource={mdxSource}
|
||||
/>
|
||||
<DocsPageActions mdxSource={mdxSource} />
|
||||
</div>
|
||||
<DocsDescription className="wrap-anywhere">
|
||||
{page.data.description}
|
||||
|
|
|
|||
|
|
@ -2,109 +2,37 @@
|
|||
|
||||
import { useState } from "react";
|
||||
|
||||
type CopyState = "idle" | "copied" | "error";
|
||||
|
||||
type Props = {
|
||||
markdownUrl: string;
|
||||
mdxSource: string;
|
||||
};
|
||||
|
||||
export function DocsPageActions({ markdownUrl, mdxSource }: Props) {
|
||||
function stripFrontmatter(source: string) {
|
||||
return source.trim().replace(/^---\n[\s\S]*?\n---\n?/, "").trim();
|
||||
}
|
||||
|
||||
export function DocsPageActions({ mdxSource }: Props) {
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const onCopy = async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(stripFrontmatter(mdxSource));
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 1500);
|
||||
} catch {
|
||||
// Clipboard denied — fail silently
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="not-prose flex flex-wrap items-center gap-2 text-xs">
|
||||
<CopyMarkdownButton markdownUrl={markdownUrl} />
|
||||
<a
|
||||
href={markdownUrl}
|
||||
className="inline-flex h-8 items-center rounded-md border border-fd-border bg-fd-background px-3 font-medium text-fd-muted-foreground transition-colors hover:border-fd-primary/40 hover:text-fd-foreground"
|
||||
<button
|
||||
type="button"
|
||||
onClick={onCopy}
|
||||
className="inline-flex h-8 items-center rounded-md border border-fd-border bg-fd-background px-3 font-medium text-fd-muted-foreground transition-colors hover:border-fd-primary/40 hover:text-fd-foreground data-[state=copied]:border-emerald-500/40 data-[state=copied]:text-emerald-600"
|
||||
data-state={copied ? "copied" : "idle"}
|
||||
>
|
||||
View MD
|
||||
</a>
|
||||
<CopyTextButton label="Copy MDX" text={mdxSource} />
|
||||
{copied ? "Copied" : "Copy as Markdown"}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function CopyMarkdownButton({ markdownUrl }: { markdownUrl: string }) {
|
||||
const [state, setState] = useState<CopyState>("idle");
|
||||
|
||||
const onClick = async () => {
|
||||
try {
|
||||
const response = await fetch(markdownUrl, {
|
||||
headers: { Accept: "text/markdown" },
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch ${markdownUrl}`);
|
||||
}
|
||||
|
||||
await navigator.clipboard.writeText(await response.text());
|
||||
flash(setState, "copied");
|
||||
} catch {
|
||||
flash(setState, "error");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ActionButton
|
||||
label={labelForState(state, "Copy MD")}
|
||||
onClick={onClick}
|
||||
state={state}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function CopyTextButton({ label, text }: { label: string; text: string }) {
|
||||
const [state, setState] = useState<CopyState>("idle");
|
||||
|
||||
const onClick = async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
flash(setState, "copied");
|
||||
} catch {
|
||||
flash(setState, "error");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ActionButton
|
||||
label={labelForState(state, label)}
|
||||
onClick={onClick}
|
||||
state={state}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function ActionButton({
|
||||
label,
|
||||
onClick,
|
||||
state,
|
||||
}: {
|
||||
label: string;
|
||||
onClick: () => void;
|
||||
state: CopyState;
|
||||
}) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
className="inline-flex h-8 items-center rounded-md border border-fd-border bg-fd-background px-3 font-medium text-fd-muted-foreground transition-colors hover:border-fd-primary/40 hover:text-fd-foreground data-[state=copied]:border-emerald-500/40 data-[state=copied]:text-emerald-600 data-[state=error]:border-red-500/40 data-[state=error]:text-red-600"
|
||||
data-state={state}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function labelForState(state: CopyState, label: string) {
|
||||
if (state === "copied") return "Copied";
|
||||
if (state === "error") return "Copy failed";
|
||||
return label;
|
||||
}
|
||||
|
||||
function flash(
|
||||
setState: (state: CopyState) => void,
|
||||
state: Exclude<CopyState, "idle">,
|
||||
) {
|
||||
setState(state);
|
||||
window.setTimeout(() => setState("idle"), 1500);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue