fuzzyworld

word-waltz / files / src / components / ShareDialog.ts

ShareDialog.ts

2.0 KB · history · blame

1/**
2 * ShareDialog — shareable link + QR code UI
3 *
4 * Displays the game invite URL (with the encryption key in the fragment)
5 * and renders a QR code of that URL so the opponent can scan to join.
6 */
7
8import QRCode from 'qrcode';
9
10interface ShareDialogProps {
11 shareUrl: string;
12}
13
14export function mountShareDialog(container: HTMLElement, props: ShareDialogProps): () => void {
15 const { shareUrl } = props;
16
17 const root = document.createElement('div');
18 root.className = 'share-dialog';
19
20 const canvas = document.createElement('canvas');
21 canvas.className = 'share-dialog__qr';
22
23 const linkEl = document.createElement('a');
24 linkEl.className = 'share-dialog__link';
25 linkEl.href = shareUrl;
26 linkEl.textContent = shareUrl;
27
28 const copyBtn = document.createElement('button');
29 copyBtn.className = 'share-dialog__copy';
30 copyBtn.type = 'button';
31 copyBtn.textContent = 'Copy link';
32 let resetTimer: ReturnType<typeof setTimeout> | null = null;
33 copyBtn.addEventListener('click', () => {
34 if (copyBtn.disabled) return;
35 copyBtn.disabled = true;
36 navigator.clipboard.writeText(shareUrl).then(() => {
37 copyBtn.textContent = 'Copied!';
38 }).catch(() => {
39 copyBtn.textContent = 'Copy failed';
40 }).finally(() => {
41 if (resetTimer !== null) clearTimeout(resetTimer);
42 resetTimer = setTimeout(() => {
43 copyBtn.textContent = 'Copy link';
44 copyBtn.disabled = false;
45 }, 2000);
46 });
47 });
48
49 root.appendChild(canvas);
50 root.appendChild(linkEl);
51 root.appendChild(copyBtn);
52 container.appendChild(root);
53
54 QRCode.toCanvas(canvas, shareUrl, { width: 220, margin: 2 }).catch((err: unknown) => {
55 console.error('QR generation failed:', err);
56 canvas.style.display = 'none';
57 const qrError = document.createElement('p');
58 qrError.className = 'share-dialog__qr-error';
59 qrError.textContent = 'QR code unavailable — copy the link below.';
60 root.insertBefore(qrError, linkEl);
61 });
62
63 return function cleanup() {
64 container.removeChild(root);
65 };
66}