File tree Expand file tree Collapse file tree 5 files changed +109
-10
lines changed Expand file tree Collapse file tree 5 files changed +109
-10
lines changed Original file line number Diff line number Diff line change
1
+ import { CheckIcon , CopyIcon } from './icon' ;
2
+ import cn from 'clsx'
3
+ import type { ComponentProps , FC } from 'react'
4
+ import { useHover } from '@/lib/hooks/use-hover' ;
5
+ import { useTimed } from '@/lib/hooks/use-timed' ;
6
+
7
+ export const Code : FC <
8
+ ComponentProps < 'code' >
9
+ > = ( { children, className, ...props } ) => {
10
+ const [ copied , startCopyTimer ] = useTimed ( 1500 ) ;
11
+ const [ ref , hovering ] = useHover ( ) ;
12
+ return (
13
+ < span
14
+ ref = { ref }
15
+ className = "flex items-center gap-2 break-all rounded-md bg-black p-4 font-mono text-sm relative pr-14 border border-gray-600"
16
+ >
17
+ < code
18
+ className = { cn (
19
+ 'whitespace-pre-line' ,
20
+ 'cursor-text' ,
21
+ className ,
22
+ ) }
23
+ // always show code blocks in ltr
24
+ dir = "ltr"
25
+ { ...props }
26
+ >
27
+ { children }
28
+ </ code >
29
+ < button
30
+ data-hovering = { hovering || copied }
31
+ className = "cursor-pointer opacity-0 data-[hovering=true]:transition-opacity data-[hovering=true]:opacity-100 hover:text-orange-600 absolute right-3 top-2 p-2 border border-gray-600 rounded-md"
32
+ onClick = { async ( ev ) => {
33
+ const value = children ?. valueOf ( ) . toString ( ) ;
34
+ if ( value ) {
35
+ ev . preventDefault ( ) ;
36
+ startCopyTimer ( ) ;
37
+ await navigator . clipboard . writeText ( value ) ;
38
+ }
39
+ } }
40
+ title = "Copy to clipboard"
41
+ >
42
+ { copied ? < CheckIcon size = { 16 } /> : < CopyIcon size = { 16 } /> }
43
+ </ button >
44
+ </ span >
45
+ )
46
+ }
Original file line number Diff line number Diff line change @@ -2,10 +2,10 @@ import { ReactElement, ReactNode } from 'react';
2
2
import magnifier from '../../../public/images/figures/magnifier.svg?url' ;
3
3
import { ProjectType } from '@/gql/graphql' ;
4
4
import { cn } from '@/lib/utils' ;
5
- import { InlineCode } from '../v2/inline-code' ;
6
5
import { Card } from './card' ;
7
6
import { DocsLink } from './docs-note' ;
8
7
import { Heading } from './heading' ;
8
+ import { Code } from './code' ;
9
9
10
10
export const EmptyList = ( {
11
11
title,
@@ -68,9 +68,9 @@ export const NoSchemaVersion = ({
68
68
registry before publishing.
69
69
</ div >
70
70
< div className = "flex w-full justify-center" >
71
- < InlineCode
72
- content = { `hive schema:check ${ isDistributed ? '--service <service-name> --url <url> ' : '' } <path/schema.graphql>` }
73
- / >
71
+ < Code >
72
+ { `hive schema:check ${ isDistributed ? '--service <service-name> --url <url> ' : '' } <path/schema.graphql>` }
73
+ </ Code >
74
74
</ div >
75
75
</ >
76
76
) ;
@@ -84,9 +84,9 @@ export const NoSchemaVersion = ({
84
84
</ div >
85
85
) }
86
86
< div className = "flex w-full justify-center" >
87
- < InlineCode
88
- content = { `hive schema:publish ${ isDistributed ? '--service <service-name> --url <url> ' : '' } <path/schema.graphql>` }
89
- / >
87
+ < Code >
88
+ { `hive schema:publish ${ isDistributed ? '--service <service-name> --url <url> ' : '' } <path/schema.graphql>` }
89
+ </ Code >
90
90
</ div >
91
91
</ >
92
92
) ;
Original file line number Diff line number Diff line change @@ -231,11 +231,11 @@ export const ArrowDownIcon = ({ className }: IconProps): ReactElement => (
231
231
</ svg >
232
232
) ;
233
233
234
- export const CheckIcon = ( { className } : IconProps ) : ReactElement => (
234
+ export const CheckIcon = ( { className, size } : IconProps & { size ?: number } ) : ReactElement => (
235
235
< svg
236
236
viewBox = "0 0 24 24"
237
- width = "24"
238
- height = "24"
237
+ width = { size ?? 24 }
238
+ height = { size ?? 24 }
239
239
stroke = "currentColor"
240
240
xmlns = "http://www.w3.org/2000/svg"
241
241
className = { className }
Original file line number Diff line number Diff line change
1
+ import { useState , useCallback , useRef } from 'react' ;
2
+
3
+ export function useHover ( ) {
4
+ const [ hovering , setHovering ] = useState ( false ) ;
5
+ const previousNode = useRef < Node | null > ( null ) ;
6
+
7
+ const handleMouseEnter = useCallback ( ( ) => {
8
+ setHovering ( true ) ;
9
+ } , [ ] ) ;
10
+
11
+ const handleMouseLeave = useCallback ( ( ) => {
12
+ setHovering ( false ) ;
13
+ } , [ ] ) ;
14
+
15
+ const customRef = useCallback (
16
+ ( node : HTMLElement ) => {
17
+ if ( previousNode . current ?. nodeType === Node . ELEMENT_NODE ) {
18
+ previousNode . current . removeEventListener (
19
+ 'mouseenter' ,
20
+ handleMouseEnter
21
+ ) ;
22
+ previousNode . current . removeEventListener (
23
+ 'mouseleave' ,
24
+ handleMouseLeave
25
+ ) ;
26
+ }
27
+
28
+ if ( node ?. nodeType === Node . ELEMENT_NODE ) {
29
+ node . addEventListener ( 'mouseenter' , handleMouseEnter ) ;
30
+ node . addEventListener ( 'mouseleave' , handleMouseLeave ) ;
31
+ }
32
+
33
+ previousNode . current = node ;
34
+ } ,
35
+ [ handleMouseEnter , handleMouseLeave ]
36
+ ) ;
37
+
38
+ return [ customRef , hovering ] as const ;
39
+ }
Original file line number Diff line number Diff line change
1
+ import { useState } from 'react' ;
2
+
3
+ export function useTimed ( wait : number = 1000 ) {
4
+ const [ timer , setTimer ] = useState < NodeJS . Timeout | null > ( null ) ;
5
+ const handler = ( ) => {
6
+ if ( timer ) {
7
+ clearTimeout ( timer ) ;
8
+ }
9
+ setTimer ( setTimeout ( ( ) => {
10
+ setTimer ( null )
11
+ } , wait ) ) ;
12
+ }
13
+ return [ timer !== null , handler ] as const ;
14
+ }
You can’t perform that action at this time.
0 commit comments