Skip to content

Commit 44033bf

Browse files
committed
feat: new copy code animate
Signed-off-by: Innei <[email protected]>
1 parent 54eaf32 commit 44033bf

File tree

1 file changed

+42
-3
lines changed

1 file changed

+42
-3
lines changed

src/components/ui/code-highlighter/shiki/ShikiWrapper.tsx

+42-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import {
44
useEffect,
55
useImperativeHandle,
66
useMemo,
7+
useRef,
78
useState,
89
} from 'react'
910
import clsx from 'clsx'
11+
import { AnimatePresence, m } from 'framer-motion'
12+
import type { Variants } from 'framer-motion'
1013
import type { PropsWithChildren } from 'react'
1114

1215
import { getViewport } from '~/atoms/hooks'
@@ -28,6 +31,20 @@ interface Props {
2831
renderedHTML?: string
2932
}
3033

34+
const copyIconVariants: Variants = {
35+
initial: {
36+
opacity: 1,
37+
scale: 1,
38+
},
39+
animate: {
40+
opacity: 1,
41+
scale: 1,
42+
},
43+
exit: {
44+
opacity: 0,
45+
scale: 0,
46+
},
47+
}
3148
export const ShikiHighLighterWrapper = forwardRef<
3249
HTMLDivElement,
3350
PropsWithChildren<
@@ -43,9 +60,16 @@ export const ShikiHighLighterWrapper = forwardRef<
4360
attrs,
4461
} = props
4562

63+
const [copied, setCopied] = useState(false)
64+
const copiedTimerRef = useRef<any>()
4665
const handleCopy = useCallback(() => {
4766
navigator.clipboard.writeText(value)
48-
toast.success('已复制到剪贴板')
67+
setCopied(true)
68+
69+
clearTimeout(copiedTimerRef.current)
70+
copiedTimerRef.current = setTimeout(() => {
71+
setCopied(false)
72+
}, 2000)
4973
}, [value])
5074

5175
const [codeBlockRef, setCodeBlockRef] = useState<HTMLDivElement | null>(null)
@@ -122,16 +146,31 @@ export const ShikiHighLighterWrapper = forwardRef<
122146
<MotionButtonBase
123147
onClick={handleCopy}
124148
className={clsx(
125-
'center absolute right-2 top-2 z-[1] flex text-xs',
149+
'absolute right-2 top-2 z-[1] flex text-xs center',
126150
'rounded-md border border-accent/5 bg-accent/80 p-1.5 text-white backdrop-blur duration-200',
127151
'opacity-0 group-hover:opacity-100',
128152
filename && '!top-12',
129153
)}
130154
>
131-
<i className="icon-[mingcute--copy-2-fill] size-4" />
155+
<AnimatePresence mode="wait">
156+
{copied ? (
157+
<m.i
158+
key={'copied'}
159+
className="icon-[mingcute--check-line] size-4"
160+
{...copyIconVariants}
161+
/>
162+
) : (
163+
<m.i
164+
key={'copy'}
165+
className="icon-[mingcute--copy-2-fill] size-4"
166+
{...copyIconVariants}
167+
/>
168+
)}
169+
</AnimatePresence>
132170
</MotionButtonBase>
133171
<AutoResizeHeight spring className="relative">
134172
<div
173+
onCopy={stopPropagation}
135174
ref={setCodeBlockRef}
136175
className={clsxm(
137176
'relative max-h-[50vh] w-full overflow-auto',

0 commit comments

Comments
 (0)