profileShare

rasmusjy / roundtable

Read-only snapshot

No repository description.

main default branch 181 files Expires Sep 13, 2026, 9:06 AM

Commit

add copy-to-clipboard on final answer

commit ff35fdf

2 changed files with +52 and −13

Jump to a changed file
  1. src/components/debate/final-answer.tsx +17 −13
  2. src/components/ui/copy-button.tsx +35 −0
modified src/components/debate/final-answer.tsx +17 −13
@@ -3,6 +3,7 @@
3 3 import { AlertTriangle, Gavel } from 'lucide-react';
4 4 import { RichText } from '@/components/debate/rich-text';
5 5 import { Badge } from '@/components/ui/badge';
6 +import { CopyButton } from '@/components/ui/copy-button';
6 7 import {
7 8 Tooltip,
8 9 TooltipContent,
@@ -35,19 +36,22 @@export function FinalAnswer({
35 36 <div className="text-sm font-semibold">Chairman synthesis</div>
36 37 <div className="font-mono text-[11px] text-muted-foreground">{synthesis.model}</div>
37 38 </div>
38 - {chairmanProviderConflict && (
39 - <Tooltip>
40 - <TooltipTrigger asChild>
41 - <Badge variant="warning" className="ml-auto cursor-help gap-1">
42 - <AlertTriangle className="h-3 w-3" /> provider overlap
43 - </Badge>
44 - </TooltipTrigger>
45 - <TooltipContent className="max-w-xs">
46 - The chairman shares a provider family with a council member, a self-preference risk. Answers are shown
47 - to the chairman anonymized to mitigate it, but consider a chairman from an independent provider.
48 - </TooltipContent>
49 - </Tooltip>
50 - )}
39 + <div className="ml-auto flex items-center gap-2">
40 + {chairmanProviderConflict && (
41 + <Tooltip>
42 + <TooltipTrigger asChild>
43 + <Badge variant="warning" className="cursor-help gap-1">
44 + <AlertTriangle className="h-3 w-3" /> provider overlap
45 + </Badge>
46 + </TooltipTrigger>
47 + <TooltipContent className="max-w-xs">
48 + The chairman shares a provider family with a council member, a self-preference risk. Answers are shown
49 + to the chairman anonymized to mitigate it, but consider a chairman from an independent provider.
50 + </TooltipContent>
51 + </Tooltip>
52 + )}
53 + <CopyButton text={synthesis.finalAnswer} label="Copy answer" />
54 + </div>
51 55 </div>
52 56
53 57 <div className="p-5">
added src/components/ui/copy-button.tsx +35 −0
@@ -0,0 +1,35 @@
1 +'use client';
2 +
3 +import { Check, Copy } from 'lucide-react';
4 +import { useState } from 'react';
5 +import { Button } from '@/components/ui/button';
6 +import { cn } from '@/lib/utils';
7 +
8 +export function CopyButton({
9 + text,
10 + label = 'Copy',
11 + className,
12 +}: {
13 + text: string;
14 + label?: string;
15 + className?: string;
16 +}) {
17 + const [copied, setCopied] = useState(false);
18 +
19 + const onCopy = async () => {
20 + try {
21 + await navigator.clipboard.writeText(text);
22 + setCopied(true);
23 + setTimeout(() => setCopied(false), 1500);
24 + } catch {
25 + /* clipboard unavailable (insecure context) */
26 + }
27 + };
28 +
29 + return (
30 + <Button variant="ghost" size="sm" className={cn('gap-1.5', className)} onClick={onCopy} aria-label={label}>
31 + {copied ? <Check className="h-3.5 w-3.5" /> : <Copy className="h-3.5 w-3.5" />}
32 + {copied ? 'Copied' : label}
33 + </Button>
34 + );
35 +}