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';
22import magnifier from '../../../public/images/figures/magnifier.svg?url' ;
33import { ProjectType } from '@/gql/graphql' ;
44import { cn } from '@/lib/utils' ;
5- import { InlineCode } from '../v2/inline-code' ;
65import { Card } from './card' ;
76import { DocsLink } from './docs-note' ;
87import { Heading } from './heading' ;
8+ import { Code } from './code' ;
99
1010export const EmptyList = ( {
1111 title,
@@ -68,9 +68,9 @@ export const NoSchemaVersion = ({
6868 registry before publishing.
6969 </ div >
7070 < 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 >
7474 </ div >
7575 </ >
7676 ) ;
@@ -84,9 +84,9 @@ export const NoSchemaVersion = ({
8484 </ div >
8585 ) }
8686 < 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 >
9090 </ div >
9191 </ >
9292 ) ;
Original file line number Diff line number Diff line change @@ -231,11 +231,11 @@ export const ArrowDownIcon = ({ className }: IconProps): ReactElement => (
231231 </ svg >
232232) ;
233233
234- export const CheckIcon = ( { className } : IconProps ) : ReactElement => (
234+ export const CheckIcon = ( { className, size } : IconProps & { size ?: number } ) : ReactElement => (
235235 < svg
236236 viewBox = "0 0 24 24"
237- width = "24"
238- height = "24"
237+ width = { size ?? 24 }
238+ height = { size ?? 24 }
239239 stroke = "currentColor"
240240 xmlns = "http://www.w3.org/2000/svg"
241241 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