55 *
66 * Copyright Oxide Computer Company
77 */
8+ import * as m from 'motion/react-m'
89import { useState , type ReactNode } from 'react'
910
1011import { Success12Icon } from '@oxide/design-system/icons/react'
@@ -13,31 +14,27 @@ import { Button } from '~/ui/lib/Button'
1314import { Modal } from '~/ui/lib/Modal'
1415import { useTimeout } from '~/ui/lib/use-timeout'
1516
16- type CopyCodeProps = {
17+ type CopyCodeModalProps = {
1718 code : string
18- modalButtonText : string
1919 copyButtonText : string
2020 modalTitle : string
2121 footer ?: ReactNode
2222 /** rendered code */
2323 children ?: ReactNode
24+ isOpen : boolean
25+ onDismiss : ( ) => void
2426}
2527
26- export function CopyCode ( {
28+ export function CopyCodeModal ( {
29+ isOpen,
30+ onDismiss,
2731 code,
28- modalButtonText,
2932 copyButtonText,
3033 modalTitle,
3134 children,
3235 footer,
33- } : CopyCodeProps ) {
34- const [ isOpen , setIsOpen ] = useState ( false )
36+ } : CopyCodeModalProps ) {
3537 const [ hasCopied , setHasCopied ] = useState ( false )
36-
37- function handleDismiss ( ) {
38- setIsOpen ( false )
39- }
40-
4138 useTimeout ( ( ) => setHasCopied ( false ) , hasCopied ? 2000 : null )
4239
4340 const handleCopy = ( ) => {
@@ -47,37 +44,44 @@ export function CopyCode({
4744 }
4845
4946 return (
50- < >
51- < Button variant = "ghost" size = "sm" className = "ml-2" onClick = { ( ) => setIsOpen ( true ) } >
52- { modalButtonText }
53- </ Button >
54- < Modal isOpen = { isOpen } onDismiss = { handleDismiss } title = { modalTitle } width = "free" >
55- < Modal . Section >
56- < pre className = "w-full rounded border px-4 py-3 !normal-case !tracking-normal text-mono-md bg-default border-secondary" >
57- { children }
58- </ pre >
59- </ Modal . Section >
60- < Modal . Footer
61- onDismiss = { handleDismiss }
62- onAction = { handleCopy }
63- actionText = {
64- < >
65- < span className = { hasCopied ? 'invisible' : '' } > { copyButtonText } </ span >
66- < span
67- className = { `absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center ${
68- hasCopied ? '' : 'invisible'
69- } `}
47+ < Modal isOpen = { isOpen } onDismiss = { onDismiss } title = { modalTitle } width = "free" >
48+ < Modal . Section >
49+ < pre className = "w-full rounded border px-4 py-3 !normal-case !tracking-normal text-mono-md bg-default border-secondary" >
50+ { children }
51+ </ pre >
52+ </ Modal . Section >
53+ < Modal . Footer
54+ onDismiss = { onDismiss }
55+ onAction = { handleCopy }
56+ actionText = {
57+ < >
58+ < m . span
59+ className = "flex items-center"
60+ animate = { {
61+ opacity : hasCopied ? 0 : 1 ,
62+ y : hasCopied ? 25 : 0 ,
63+ } }
64+ transition = { { type : 'spring' , duration : 0.3 , bounce : 0 } }
65+ >
66+ { copyButtonText }
67+ </ m . span >
68+
69+ { hasCopied && (
70+ < m . span
71+ animate = { { opacity : 1 , y : '-50%' , x : '-50%' } }
72+ initial = { { opacity : 0 , y : 'calc(-50% - 25px)' , x : '-50%' } }
73+ transition = { { type : 'spring' , duration : 0.3 , bounce : 0 } }
74+ className = "absolute left-1/2 top-1/2 flex items-center"
7075 >
71- < Success12Icon className = "mr-2 text-accent" />
72- Copied
73- </ span >
74- </ >
75- }
76- >
77- { footer }
78- </ Modal . Footer >
79- </ Modal >
80- </ >
76+ < Success12Icon className = "text-accent" />
77+ </ m . span >
78+ ) }
79+ </ >
80+ }
81+ >
82+ { footer }
83+ </ Modal . Footer >
84+ </ Modal >
8185 )
8286}
8387
@@ -90,15 +94,23 @@ export function EquivalentCliCommand({ project, instance }: EquivProps) {
9094 `--instance ${ instance } ` ,
9195 ]
9296
97+ const [ isOpen , setIsOpen ] = useState ( false )
98+
9399 return (
94- < CopyCode
95- code = { cmdParts . join ( ' ' ) }
96- modalButtonText = "Equivalent CLI Command"
97- copyButtonText = "Copy command"
98- modalTitle = "CLI command"
99- >
100- < span className = "mr-2 select-none text-tertiary" > $</ span >
101- { cmdParts . join ( ' \\\n ' ) }
102- </ CopyCode >
100+ < >
101+ < Button variant = "ghost" size = "sm" className = "ml-2" onClick = { ( ) => setIsOpen ( true ) } >
102+ Equivalent CLI Command
103+ </ Button >
104+ < CopyCodeModal
105+ code = { cmdParts . join ( ' ' ) }
106+ copyButtonText = "Copy command"
107+ modalTitle = "CLI command"
108+ isOpen = { isOpen }
109+ onDismiss = { ( ) => setIsOpen ( false ) }
110+ >
111+ < span className = "mr-2 select-none text-tertiary" > $</ span >
112+ { cmdParts . join ( ' \\\n ' ) }
113+ </ CopyCodeModal >
114+ </ >
103115 )
104116}
0 commit comments