Skip to content

Commit c524001

Browse files
authored
feat: add copy buttons (#43)
1 parent 6a8eba0 commit c524001

File tree

1 file changed

+56
-18
lines changed

1 file changed

+56
-18
lines changed

components/welcome.tsx

Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
'use client';
22

3-
import { useMemo, useState } from 'react';
3+
import { useCallback, useMemo, useState } from 'react';
44
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
55
import { motion } from 'motion/react';
6-
import { HandPointingIcon } from '@phosphor-icons/react';
6+
import { CheckIcon, CopyIcon, HandPointingIcon } from '@phosphor-icons/react';
77
import { APP_CONFIG_DEFAULTS } from '@/app-config';
88
import { THEME_STORAGE_KEY } from '@/lib/env';
99
import type { ThemeMode } from '@/lib/types';
1010
import { cn } from '@/lib/utils';
1111
import EmbedPopupAgentClient from './embed-popup/agent-client';
1212
import { ThemeToggle } from './theme-toggle';
13+
import { Button } from './ui/button';
1314

1415
export default function Welcome() {
1516
const router = useRouter();
@@ -20,17 +21,35 @@ export default function Welcome() {
2021
const [, forceUpdate] = useState(0);
2122
const theme = (localStorage.getItem(THEME_STORAGE_KEY) as ThemeMode) ?? 'dark';
2223

23-
const embedUrl = useMemo(() => {
24+
const [copied, setCopied] = useState(false);
25+
const copyEmbedCode = useCallback((embedCode: string) => {
26+
navigator.clipboard.writeText(embedCode);
27+
28+
setCopied(true);
29+
setTimeout(() => {
30+
setCopied(false);
31+
}, 1000);
32+
}, []);
33+
34+
const iframeEmbedUrl = useMemo(() => {
2435
const url = new URL('/embed', window.location.origin);
2536
url.searchParams.set('theme', theme);
2637
return url.toString();
2738
}, [theme]);
2839

29-
const embedPopupUrl = useMemo(() => {
40+
const popupEmbedUrl = useMemo(() => {
3041
const url = new URL('/embed-popup.js', window.location.origin);
3142
return url.toString();
3243
}, []);
3344

45+
const popupEmbedCode = useMemo(
46+
() => `<script\n src="${popupEmbedUrl}"\n></script>`,
47+
[popupEmbedUrl]
48+
);
49+
const iframeEmbedCode = useMemo(() => {
50+
return `<iframe\n src="${iframeEmbedUrl}"\n style="width: 320px; height: 64px;"\n></iframe>`;
51+
}, [iframeEmbedUrl]);
52+
3453
const popupTestUrl = useMemo(() => {
3554
const url = new URL('/popup', window.location.origin);
3655
return url.toString();
@@ -102,24 +121,38 @@ export default function Welcome() {
102121
<h3 className="sr-only text-lg font-semibold">IFrame Style</h3>
103122
<div>
104123
<h4 className="text-fg0 mb-1 font-semibold">Embed code</h4>
105-
<pre className="border-separator2 bg-bg2 overflow-auto rounded-md border px-2 py-1">
124+
<pre className="border-separator2 bg-bg2 relative overflow-auto rounded-md border px-2 py-1">
106125
<code className="font-mono">
107-
{`<iframe\n src="`}
108-
<a
109-
href={embedUrl}
110-
target="_blank"
111-
rel="noopener noreferrer"
112-
className="text-primary underline"
113-
>
114-
{embedUrl}
115-
</a>
116-
{`"\n style="width: 320px; height: 64px;"\n></iframe>`}
126+
{iframeEmbedCode.split(iframeEmbedUrl).map((stringPart, index) => {
127+
if (index === 0) {
128+
return <span key={index}>{stringPart}</span>;
129+
}
130+
131+
return (
132+
<span key={index}>
133+
<a
134+
href={iframeEmbedUrl}
135+
target="_blank"
136+
rel="noopener noreferrer"
137+
className="text-primary underline"
138+
>
139+
{iframeEmbedUrl}
140+
</a>
141+
{stringPart}
142+
</span>
143+
);
144+
})}
117145
</code>
146+
<div className="absolute top-0 right-0">
147+
<Button onClick={() => copyEmbedCode(iframeEmbedCode)}>
148+
{copied ? <CheckIcon className="text-fgSuccess" /> : <CopyIcon />}
149+
</Button>
150+
</div>
118151
</pre>
119152
</div>
120153
<div className="flex justify-center">
121154
<iframe
122-
src={embedUrl}
155+
src={iframeEmbedUrl}
123156
style={{ width: 320, height: 64 }}
124157
className="opacity-100 transition-opacity duration-500 [@starting-style]:opacity-0"
125158
/>
@@ -132,8 +165,13 @@ export default function Welcome() {
132165
<h3 className="sr-only text-lg font-semibold">Popup Style</h3>
133166
<div>
134167
<h4 className="text-fg0 mb-1 font-semibold">Embed code</h4>
135-
<pre className="border-separator2 bg-bg2 overflow-auto rounded-md border px-2 py-1">
136-
<code className="font-mono">{`<script src="${embedPopupUrl}"></script>`}</code>
168+
<pre className="border-separator2 bg-bg2 relative overflow-auto rounded-md border px-2 py-1">
169+
<code className="font-mono">{popupEmbedCode}</code>
170+
<div className="absolute top-0 right-0">
171+
<Button onClick={() => copyEmbedCode(popupEmbedCode)}>
172+
{copied ? <CheckIcon className="text-fgSuccess" /> : <CopyIcon />}
173+
</Button>
174+
</div>
137175
</pre>
138176
<p className="text-fg4 my-4 text-sm">
139177
To apply local changes, run{' '}

0 commit comments

Comments
 (0)