@@ -14,8 +14,12 @@ import Tag from 'components/Tag';
1414import { H1 } from './MDX/Heading' ;
1515import type { RouteTag , RouteItem } from './Layout/getRouteMeta' ;
1616import * as React from 'react' ;
17+ import { useState , useEffect } from 'react' ;
18+ import { useRouter } from 'next/router' ;
1719import { IconCanary } from './Icon/IconCanary' ;
1820import { IconExperimental } from './Icon/IconExperimental' ;
21+ import { IconCopy } from './Icon/IconCopy' ;
22+ import { Button } from './Button' ;
1923
2024interface PageHeadingProps {
2125 title : string ;
@@ -27,18 +31,67 @@ interface PageHeadingProps {
2731 breadcrumbs : RouteItem [ ] ;
2832}
2933
34+ function CopyAsMarkdownButton ( ) {
35+ const { asPath} = useRouter ( ) ;
36+ const [ copied , setCopied ] = useState ( false ) ;
37+
38+ useEffect ( ( ) => {
39+ if ( ! copied ) return ;
40+ const timer = setTimeout ( ( ) => setCopied ( false ) , 2000 ) ;
41+ return ( ) => clearTimeout ( timer ) ;
42+ } , [ copied ] ) ;
43+
44+ async function fetchPageBlob ( ) {
45+ const cleanPath = asPath . split ( / [ ? # ] / ) [ 0 ] ;
46+ const res = await fetch ( cleanPath + '.md' ) ;
47+ if ( ! res . ok ) throw new Error ( 'Failed to fetch' ) ;
48+ const text = await res . text ( ) ;
49+ return new Blob ( [ text ] , { type : 'text/plain' } ) ;
50+ }
51+
52+ async function handleCopy ( ) {
53+ try {
54+ await navigator . clipboard . write ( [
55+ // Don't wait for the blob, or Safari will refuse clipboard access
56+ new ClipboardItem ( { 'text/plain' : fetchPageBlob ( ) } ) ,
57+ ] ) ;
58+ setCopied ( true ) ;
59+ } catch {
60+ // Silently fail
61+ }
62+ }
63+
64+ return (
65+ < Button onClick = { handleCopy } className = "text-sm py-1 px-3" >
66+ < IconCopy className = "w-3.5 h-3.5 me-1.5" />
67+ { copied ? (
68+ 'Copied!'
69+ ) : (
70+ < >
71+ < span className = "hidden sm:inline" > Copy page</ span >
72+ < span className = "sm:hidden" > Copy</ span >
73+ </ >
74+ ) }
75+ </ Button >
76+ ) ;
77+ }
78+
3079function PageHeading ( {
3180 title,
3281 status,
3382 version,
3483 tags = [ ] ,
3584 breadcrumbs,
3685} : PageHeadingProps ) {
37- console . log ( 'version' , version ) ;
3886 return (
3987 < div className = "px-5 sm:px-12 pt-3.5" >
4088 < div className = "max-w-4xl ms-0 2xl:mx-auto" >
41- { breadcrumbs ? < Breadcrumbs breadcrumbs = { breadcrumbs } /> : null }
89+ < div className = "flex justify-between items-start" >
90+ < div className = "flex-1" >
91+ { breadcrumbs ? < Breadcrumbs breadcrumbs = { breadcrumbs } /> : null }
92+ </ div >
93+ < CopyAsMarkdownButton />
94+ </ div >
4295 < H1 className = "mt-0 text-primary dark:text-primary-dark -mx-.5 break-words" >
4396 { title }
4497 { version === 'canary' && (
0 commit comments