From 0087c47cb001c66d3f01468a348a2d354a754f8d Mon Sep 17 00:00:00 2001 From: MH4GF Date: Sun, 22 Oct 2023 19:19:22 +0900 Subject: [PATCH] feat: implement copy to clipboard button --- .../CopyToClipboardButton.tsx | 34 +++++++++++++++++++ .../CopyToClipboardButton/Tooltip.tsx | 25 ++++++++++++++ .../_features/CopyToClipboardButton/index.ts | 1 + .../useSuccessTooltip.tsx | 16 +++++++++ web/src/app/page.tsx | 4 +++ 5 files changed, 80 insertions(+) create mode 100644 web/src/app/_features/CopyToClipboardButton/CopyToClipboardButton.tsx create mode 100644 web/src/app/_features/CopyToClipboardButton/Tooltip.tsx create mode 100644 web/src/app/_features/CopyToClipboardButton/index.ts create mode 100644 web/src/app/_features/CopyToClipboardButton/useSuccessTooltip.tsx diff --git a/web/src/app/_features/CopyToClipboardButton/CopyToClipboardButton.tsx b/web/src/app/_features/CopyToClipboardButton/CopyToClipboardButton.tsx new file mode 100644 index 0000000..e79d499 --- /dev/null +++ b/web/src/app/_features/CopyToClipboardButton/CopyToClipboardButton.tsx @@ -0,0 +1,34 @@ +import type { FC } from 'react' +import { useCallback, useState } from 'react' + +import { Tooltip } from './Tooltip' +import { useSuccessTooltip } from './useSuccessTooltip' + +import { Button } from '@/app/_components' + +interface Props { + text: string +} + +export const CopyToClipboardButton: FC = ({ text }) => { + const [isLoading, setIsLoading] = useState(false) + const [showTooltip, setShowTooltip] = useSuccessTooltip() + + const handleClick = useCallback(() => { + setIsLoading(true) + navigator.clipboard + .writeText(text) + .then(() => setShowTooltip(true)) + .catch((e) => console.error(e)) + setIsLoading(false) + }, [text, setShowTooltip]) + + return ( + + + + + ) +} diff --git a/web/src/app/_features/CopyToClipboardButton/Tooltip.tsx b/web/src/app/_features/CopyToClipboardButton/Tooltip.tsx new file mode 100644 index 0000000..3bef886 --- /dev/null +++ b/web/src/app/_features/CopyToClipboardButton/Tooltip.tsx @@ -0,0 +1,25 @@ +import clsx from 'clsx' +import type { FC } from 'react' + +interface Props { + show: boolean +} + +export const Tooltip: FC = ({ show: show }) => { + return ( + + Copied!! + + ) +} diff --git a/web/src/app/_features/CopyToClipboardButton/index.ts b/web/src/app/_features/CopyToClipboardButton/index.ts new file mode 100644 index 0000000..a55012b --- /dev/null +++ b/web/src/app/_features/CopyToClipboardButton/index.ts @@ -0,0 +1 @@ +export * from './CopyToClipboardButton' diff --git a/web/src/app/_features/CopyToClipboardButton/useSuccessTooltip.tsx b/web/src/app/_features/CopyToClipboardButton/useSuccessTooltip.tsx new file mode 100644 index 0000000..076ca1c --- /dev/null +++ b/web/src/app/_features/CopyToClipboardButton/useSuccessTooltip.tsx @@ -0,0 +1,16 @@ +import { useEffect, useState } from 'react' + +export const useSuccessTooltip = () => { + const [show, setShow] = useState(false) + + useEffect(() => { + if (!show) return + + const timer = setTimeout(() => { + setShow(false) + }, 2000) + return () => clearTimeout(timer) + }, [show]) + + return [show, setShow] as const +} diff --git a/web/src/app/page.tsx b/web/src/app/page.tsx index b3dd61e..db48a85 100644 --- a/web/src/app/page.tsx +++ b/web/src/app/page.tsx @@ -8,6 +8,7 @@ import { } from 'react-dom' import { Button, Header, GistIdInput } from './_components' +import { CopyToClipboardButton } from './_features/CopyToClipboardButton' import { showList } from './showList' interface SubmitButtonProps { @@ -59,6 +60,9 @@ function Home() { focus:ring-2 focus:ring-inset focus:ring-slate-600 sm:text-sm sm:leading-6" defaultValue={state.result} /> +
+ +