Skip to content

Commit 8620ab2

Browse files
authored
improvement(docs): added a copy page button to the docs pages (#1743)
* improvement(docs): added a copy page button to the docs pages * added copy page button & fixed TOC alignment
1 parent 47ddfb6 commit 8620ab2

File tree

4 files changed

+80
-11
lines changed

4 files changed

+80
-11
lines changed

apps/docs/app/[lang]/[[...slug]]/page.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Link from 'next/link'
66
import { notFound } from 'next/navigation'
77
import { StructuredData } from '@/components/structured-data'
88
import { CodeBlock } from '@/components/ui/code-block'
9+
import { CopyPageButton } from '@/components/ui/copy-page-button'
910
import { source } from '@/lib/source'
1011

1112
export const dynamic = 'force-dynamic'
@@ -193,8 +194,19 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l
193194
component: <CustomFooter />,
194195
}}
195196
>
196-
<DocsTitle>{page.data.title}</DocsTitle>
197-
<DocsDescription>{page.data.description}</DocsDescription>
197+
<div className='relative'>
198+
<div className='absolute top-1 right-0'>
199+
<CopyPageButton
200+
content={`# ${page.data.title}
201+
202+
${page.data.description || ''}
203+
204+
${page.data.content || ''}`}
205+
/>
206+
</div>
207+
<DocsTitle>{page.data.title}</DocsTitle>
208+
<DocsDescription>{page.data.description}</DocsDescription>
209+
</div>
198210
<DocsBody>
199211
<MDX
200212
components={{

apps/docs/app/global.css

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@
3636
/* Shift the sidebar slightly left from the content edge for extra breathing room */
3737
--sidebar-shift: 90px;
3838
--sidebar-offset: max(0px, calc(var(--edge-gutter) - var(--sidebar-shift)));
39-
--toc-offset: var(--edge-gutter);
39+
/* Shift TOC slightly right to match sidebar spacing for symmetry */
40+
--toc-shift: 90px;
41+
--toc-offset: max(0px, calc(var(--edge-gutter) - var(--toc-shift)));
4042
/* Sidebar and TOC have 20px internal padding - navbar accounts for this directly */
4143
/* Extra gap between sidebar/TOC and the main text content */
4244
--content-gap: 1.75rem;
@@ -107,8 +109,21 @@ aside#nd-sidebar {
107109
aside#nd-sidebar {
108110
left: var(--sidebar-offset) !important;
109111
}
110-
[data-toc] {
111-
margin-right: var(--toc-offset) !important;
112+
/* TOC positioning - target all possible selectors */
113+
[data-toc],
114+
aside[data-toc],
115+
div[data-toc],
116+
.fd-toc,
117+
#nd-toc,
118+
nav[data-toc],
119+
aside:has([role="complementary"]) {
120+
right: var(--toc-offset) !important;
121+
}
122+
123+
/* Alternative TOC container targeting */
124+
[data-docs-page] > aside:last-child,
125+
main ~ aside {
126+
right: var(--toc-offset) !important;
112127
}
113128
}
114129

apps/docs/components/navbar/navbar.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ export function Navbar() {
1919
{/* Desktop: Single row layout */}
2020
<div className='hidden h-16 w-full items-center lg:flex'>
2121
<div
22-
className='grid w-full grid-cols-[auto_1fr_auto] items-center'
22+
className='relative flex w-full items-center justify-between'
2323
style={{
2424
paddingLeft: 'calc(var(--sidebar-offset) + 20px)',
25-
paddingRight: 'calc(var(--toc-offset) + 20px)',
25+
paddingRight: 'calc(var(--toc-offset) + 60px)',
2626
}}
2727
>
28-
{/* Left cluster: translate by sidebar delta to align with sidebar edge */}
28+
{/* Left cluster: logo */}
2929
<div className='flex items-center'>
3030
<Link href='/' className='flex min-w-[100px] items-center'>
3131
<Image
@@ -38,12 +38,12 @@ export function Navbar() {
3838
</Link>
3939
</div>
4040

41-
{/* Center cluster: search */}
42-
<div className='flex flex-1 items-center justify-center pl-32'>
41+
{/* Center cluster: search - absolutely positioned to center */}
42+
<div className='-translate-x-1/2 absolute left-1/2 flex items-center justify-center'>
4343
<SearchTrigger />
4444
</div>
4545

46-
{/* Right cluster aligns with TOC edge using the same right gutter */}
46+
{/* Right cluster aligns with TOC edge */}
4747
<div className='flex items-center gap-4'>
4848
<Link
4949
href='https://sim.ai'
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
'use client'
2+
3+
import { useState } from 'react'
4+
import { Check, Copy } from 'lucide-react'
5+
6+
interface CopyPageButtonProps {
7+
content: string
8+
}
9+
10+
export function CopyPageButton({ content }: CopyPageButtonProps) {
11+
const [copied, setCopied] = useState(false)
12+
13+
const handleCopy = async () => {
14+
try {
15+
await navigator.clipboard.writeText(content)
16+
setCopied(true)
17+
setTimeout(() => setCopied(false), 2000)
18+
} catch (err) {
19+
console.error('Failed to copy:', err)
20+
}
21+
}
22+
23+
return (
24+
<button
25+
onClick={handleCopy}
26+
className='flex items-center gap-1.5 rounded-lg border border-border/40 bg-background px-2.5 py-1.5 text-muted-foreground/60 text-sm transition-all hover:border-border hover:bg-accent/50 hover:text-muted-foreground'
27+
aria-label={copied ? 'Copied to clipboard' : 'Copy page content'}
28+
>
29+
{copied ? (
30+
<>
31+
<Check className='h-4 w-4' />
32+
<span>Copied</span>
33+
</>
34+
) : (
35+
<>
36+
<Copy className='h-4 w-4' />
37+
<span>Copy page</span>
38+
</>
39+
)}
40+
</button>
41+
)
42+
}

0 commit comments

Comments
 (0)