From 5009391f4a053dbc58d811c665bd3a15bc59394d Mon Sep 17 00:00:00 2001 From: Xavi Alfaro Date: Tue, 9 Apr 2024 23:43:54 -0500 Subject: [PATCH] fix clipboard on safari --- src/components/copySvg.svelte | 58 +++++++++++------------------ src/routes/api/svgs/svgr/+server.ts | 2 +- src/utils/clipboard.ts | 15 ++++++++ src/utils/getReactComponentCode.ts | 23 ++++++++++++ src/utils/getSvgContent.ts | 12 +++--- 5 files changed, 66 insertions(+), 44 deletions(-) create mode 100644 src/utils/clipboard.ts create mode 100644 src/utils/getReactComponentCode.ts diff --git a/src/components/copySvg.svelte b/src/components/copySvg.svelte index 24380e3..a48dce1 100644 --- a/src/components/copySvg.svelte +++ b/src/components/copySvg.svelte @@ -6,7 +6,9 @@ import * as Popover from '@/ui/popover'; // Utils: - import { MIMETYPE, getSvgContent } from '@/utils/getSvgContent'; + import { getSvgContent } from '@/utils/getSvgContent'; + import { getReactComponentCode } from '@/utils/getReactComponentCode'; + import { clipboard } from '@/utils/clipboard'; import { copyToClipboard as figmaCopyToClipboard } from '@/figma/copy-to-clipboard'; import { buttonStyles } from '@/ui/styles'; import { cn } from '@/utils/cn'; @@ -64,22 +66,12 @@ const svgUrlToCopy = getSvgUrl(); optionsOpen = false; - const data = { - [MIMETYPE]: getSvgContent(svgUrlToCopy, true) - }; - + const content = await getSvgContent(svgUrlToCopy); if (isInFigma) { - const content = (await getSvgContent(svgUrlToCopy, false)) as string; figmaCopyToClipboard(content); } - try { - const clipboardItem = new ClipboardItem(data); - await navigator.clipboard.write([clipboardItem]); - } catch (error) { - const content = (await getSvgContent(svgUrlToCopy, false)) as string; - await navigator.clipboard.writeText(content); - } + await clipboard(content); const category = Array.isArray(svgInfo.category) ? svgInfo.category.sort().join(' - ') @@ -111,32 +103,26 @@ isLoading = true; - try { - const title = svgInfo.title.split(' ').join(''); - const content = (await getSvgContent(svgUrlToCopy, false)) as string; - const getCode = await fetch('/api/svgs/svgr', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ code: content, typescript: tsx, name: title }) - }); - const data = await getCode.json(); - const clipboardItem = new ClipboardItem({ - 'text/plain': new Blob([data], { type: 'text/plain' }) - }); - await navigator.clipboard.write([clipboardItem]); - toast.success(`Copied as React ${tsx ? 'TSX' : 'JSX'} component`, { - description: `${svgInfo.title} - ${svgInfo.category}` - }); - } catch (error) { - toast.error('Failed to copy as React component', { - description: `${error}`, + const title = svgInfo.title.split(' ').join(''); + const content = await getSvgContent(svgUrlToCopy); + const dataComponent = { code: content, typescript: tsx, name: title }; + const { data, error } = await getReactComponentCode(dataComponent); + + if (error || !data) { + toast.error('Failed to fetch React component', { + description: `${error ?? ''}`, duration: 5000 }); - } finally { - isLoading = false; + return; } + + await clipboard(data); + + toast.success(`Copied as React ${tsx ? 'TSX' : 'JSX'} component`, { + description: `${svgInfo.title} - ${svgInfo.category}` + }); + + isLoading = false; }; diff --git a/src/routes/api/svgs/svgr/+server.ts b/src/routes/api/svgs/svgr/+server.ts index bb59ab1..715f6ff 100644 --- a/src/routes/api/svgs/svgr/+server.ts +++ b/src/routes/api/svgs/svgr/+server.ts @@ -41,7 +41,7 @@ export const POST = async ({ request }: RequestEvent) => { { componentName: name } ); - return json(jsCode, { status: 200 }); + return json({ data: jsCode }, { status: 200 }); } catch (error) { return json( { error: `Error al transformar el SVG a componente React: ${error}` }, diff --git a/src/utils/clipboard.ts b/src/utils/clipboard.ts new file mode 100644 index 0000000..d3de08b --- /dev/null +++ b/src/utils/clipboard.ts @@ -0,0 +1,15 @@ +const MIMETYPE = 'text/plain'; + +export const clipboard = async (content: string) => { + try { + const clipboardItem = new ClipboardItem({ + [MIMETYPE]: new Blob([content], { type: MIMETYPE }) + }); + + setTimeout(async () => { + await navigator.clipboard.write([clipboardItem]); + }, 200); + } catch (error) { + await navigator.clipboard.writeText(content); + } +}; diff --git a/src/utils/getReactComponentCode.ts b/src/utils/getReactComponentCode.ts new file mode 100644 index 0000000..258fb8e --- /dev/null +++ b/src/utils/getReactComponentCode.ts @@ -0,0 +1,23 @@ +interface iComponentCode { + code: string; + name: string; + typescript: boolean; +} + +export const getReactComponentCode = async ( + params: iComponentCode +): Promise<{ data?: string; error?: string }> => { + try { + const getCode = await fetch('/api/svgs/svgr', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(params) + }); + const data = await getCode.json(); + return data; + } catch (error) { + return { error: 'An error has ocurred. Try again.' }; + } +}; diff --git a/src/utils/getSvgContent.ts b/src/utils/getSvgContent.ts index 82d9b4b..664fc9e 100644 --- a/src/utils/getSvgContent.ts +++ b/src/utils/getSvgContent.ts @@ -1,7 +1,5 @@ -export const MIMETYPE = 'text/plain'; -export const getSvgContent = async (url: string | undefined, isSupported: boolean) => { - const response = await fetch(url || ''); - const content = await response.text(); - const blob = new Blob([content], { type: MIMETYPE }); - return isSupported ? blob : content; -}; \ No newline at end of file +export const getSvgContent = async (url: string | undefined) => { + const response = await fetch(url || ''); + const content = await response.text(); + return content; +};