profileShare

rasmusjy / roundtable

Read-only snapshot

No repository description.

main default branch 181 files Expires Sep 13, 2026, 9:06 AM
debate-actions.tsx 2,609 bytes
1 'use client';
2
3 import { Check, Download, RotateCcw, Share2 } from 'lucide-react';
4 import Link from 'next/link';
5 import { useState } from 'react';
6 import { Button } from '@/components/ui/button';
7 import { toast } from '@/components/ui/sonner';
8 import { truncate } from '@/lib/utils';
9
10 export function DebateActions({ debateId, question }: { debateId: string; question: string }) {
11 const [shared, setShared] = useState(false);
12 const [sharing, setSharing] = useState(false);
13
14 const share = async () => {
15 setSharing(true);
16 try {
17 const response = await fetch(`/api/debates/${debateId}/share`, { method: 'POST' });
18 if (!response.ok) throw new Error('share failed');
19 const { url } = (await response.json()) as { url: string };
20 const text = `I asked several AI models: "${truncate(question, 120)}" See where they agreed and what changed.`;
21
22 if (navigator.share) {
23 try {
24 await navigator.share({ title: 'Roundtable verdict', text, url });
25 setShared(true);
26 return;
27 } catch (error) {
28 if (error instanceof DOMException && error.name === 'AbortError') return;
29 }
30 }
31
32 const copied = await copyText(url);
33 if (!copied) throw new Error('copy failed');
34 setShared(true);
35 toast.success('Verdict link copied');
36 } catch {
37 toast.error('Could not create a share link');
38 } finally {
39 setSharing(false);
40 }
41 };
42
43 return (
44 <div className="flex flex-wrap items-center gap-2">
45 <Button size="sm" onClick={share} disabled={sharing}>
46 {shared ? <Check className="h-3.5 w-3.5" /> : <Share2 className="h-3.5 w-3.5" />}
47 {shared ? 'Shared' : sharing ? 'Preparing...' : 'Share verdict'}
48 </Button>
49 <Button variant="outline" size="sm" asChild>
50 <Link href={`/debate?from=${debateId}`}>
51 <RotateCcw className="h-3.5 w-3.5" /> Ask again
52 </Link>
53 </Button>
54 <Button variant="outline" size="sm" asChild>
55 <a href={`/api/debates/${debateId}/export?format=md`} download>
56 <Download className="h-3.5 w-3.5" /> Download
57 </a>
58 </Button>
59 </div>
60 );
61 }
62
63 async function copyText(value: string): Promise<boolean> {
64 try {
65 await navigator.clipboard.writeText(value);
66 return true;
67 } catch {
68 const input = document.createElement('textarea');
69 input.value = value;
70 input.style.position = 'fixed';
71 input.style.opacity = '0';
72 document.body.appendChild(input);
73 input.select();
74 const copied = document.execCommand('copy');
75 input.remove();
76 return copied;
77 }
78 }
79