Skip to content

Commit e5e5dcc

Browse files
committed
[Portal] Add Copy Page button to documentation pages
Add a global "Copy Page" button to all documentation pages, allowing users to copy the entire page content with one click instead of manually selecting text from top to bottom.
1 parent c7ff3b1 commit e5e5dcc

File tree

2 files changed

+60
-3
lines changed

2 files changed

+60
-3
lines changed

apps/portal/src/components/Layouts/DocLayout.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
type SidebarLink,
77
} from "../others/Sidebar";
88
import { TableOfContentsSideBar } from "../others/TableOfContents";
9+
import { CopyPageButton } from "../others/CopyPageButton";
910

1011
export type SideBar = {
1112
name: string;
@@ -58,9 +59,12 @@ export function DocLayout(props: DocLayoutProps) {
5859
data-noindex={props.noIndex}
5960
>
6061
<div className="grow xl:mt-6">
61-
<h5 className="mb-2 text-sm text-muted-foreground">
62-
{props.sideBar.name}
63-
</h5>
62+
<div className="flex items-center justify-between mb-2">
63+
<h5 className="text-sm text-muted-foreground">
64+
{props.sideBar.name}
65+
</h5>
66+
<CopyPageButton />
67+
</div>
6468
{props.children}
6569
</div>
6670
<div className="mt-16 xl:mt-20">
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"use client";
2+
3+
import { CheckIcon, CopyIcon } from "lucide-react";
4+
import { useState } from "react";
5+
import { Button } from "../ui/button";
6+
7+
export function CopyPageButton() {
8+
const [copied, setCopied] = useState(false);
9+
10+
const handleCopy = async () => {
11+
try {
12+
// Get the main content element
13+
const mainElement = document.querySelector("main");
14+
if (!mainElement) {
15+
return;
16+
}
17+
18+
// Get text content, preserving some structure
19+
const textContent = mainElement.innerText || mainElement.textContent || "";
20+
21+
await navigator.clipboard.writeText(textContent);
22+
setCopied(true);
23+
24+
// Reset after 2 seconds
25+
setTimeout(() => {
26+
setCopied(false);
27+
}, 2000);
28+
} catch (error) {
29+
console.error("Failed to copy page content:", error);
30+
}
31+
};
32+
33+
return (
34+
<Button
35+
variant="outline"
36+
size="sm"
37+
onClick={handleCopy}
38+
className="gap-2"
39+
>
40+
{copied ? (
41+
<>
42+
<CheckIcon className="size-4" />
43+
Copied!
44+
</>
45+
) : (
46+
<>
47+
<CopyIcon className="size-4" />
48+
Copy Page
49+
</>
50+
)}
51+
</Button>
52+
);
53+
}

0 commit comments

Comments
 (0)