Skip to content

Commit 1e3a2da

Browse files
0skiOskar Otwinowski
authored andcommitted
feat(CopyableText): Add text-below variant with click-to-copy tooltip
Add new text-below variant that shows "Click to copy" tooltip on hover and "Copied" on click. Also add controlled open/onOpenChange props to SimpleTooltip for managing tooltip visibility.
1 parent 1d27933 commit 1e3a2da

File tree

3 files changed

+78
-40
lines changed

3 files changed

+78
-40
lines changed

apps/webapp/app/components/primitives/CopyableText.tsx

Lines changed: 71 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -9,53 +9,87 @@ export function CopyableText({
99
copyValue,
1010
className,
1111
asChild,
12+
variant,
1213
}: {
1314
value: string;
1415
copyValue?: string;
1516
className?: string;
1617
asChild?: boolean;
18+
variant?: "icon-right" | "text-below";
1719
}) {
1820
const [isHovered, setIsHovered] = useState(false);
1921
const { copy, copied } = useCopy(copyValue ?? value);
2022

21-
return (
22-
<span
23-
className={cn("group relative inline-flex h-6 items-center", className)}
24-
onMouseLeave={() => setIsHovered(false)}
25-
>
26-
<span onMouseEnter={() => setIsHovered(true)}>{value}</span>
23+
variant = variant ?? "icon-right";
24+
25+
if (variant === "icon-right") {
26+
return (
2727
<span
28-
onClick={copy}
29-
onMouseDown={(e) => e.stopPropagation()}
30-
className={cn(
31-
"absolute -right-6 top-0 z-10 size-6 font-sans",
32-
isHovered ? "flex" : "hidden"
33-
)}
28+
className={cn("group relative inline-flex h-6 items-center", className)}
29+
onMouseLeave={() => setIsHovered(false)}
3430
>
35-
<SimpleTooltip
36-
button={
37-
<span
38-
className={cn(
39-
"ml-1 flex size-6 items-center justify-center rounded border border-charcoal-650 bg-charcoal-750",
40-
asChild && "p-1",
41-
copied
42-
? "text-green-500"
43-
: "text-text-dimmed hover:border-charcoal-600 hover:bg-charcoal-700 hover:text-text-bright"
44-
)}
45-
>
46-
{copied ? (
47-
<ClipboardCheckIcon className="size-3.5" />
48-
) : (
49-
<ClipboardIcon className="size-3.5" />
50-
)}
51-
</span>
52-
}
53-
content={copied ? "Copied!" : "Copy"}
54-
className="font-sans"
55-
disableHoverableContent
56-
asChild={asChild}
57-
/>
31+
<span onMouseEnter={() => setIsHovered(true)}>{value}</span>
32+
<span
33+
onClick={copy}
34+
onMouseDown={(e) => e.stopPropagation()}
35+
className={cn(
36+
"absolute -right-6 top-0 z-10 size-6 font-sans",
37+
isHovered ? "flex" : "hidden"
38+
)}
39+
>
40+
<SimpleTooltip
41+
button={
42+
<span
43+
className={cn(
44+
"ml-1 flex size-6 items-center justify-center rounded border border-charcoal-650 bg-charcoal-750",
45+
asChild && "p-1",
46+
copied
47+
? "text-green-500"
48+
: "text-text-dimmed hover:border-charcoal-600 hover:bg-charcoal-700 hover:text-text-bright"
49+
)}
50+
>
51+
{copied ? (
52+
<ClipboardCheckIcon className="size-3.5" />
53+
) : (
54+
<ClipboardIcon className="size-3.5" />
55+
)}
56+
</span>
57+
}
58+
content={copied ? "Copied!" : "Copy"}
59+
className="font-sans"
60+
disableHoverableContent
61+
asChild={asChild}
62+
/>
63+
</span>
5864
</span>
59-
</span>
60-
);
65+
);
66+
}
67+
68+
if (variant === "text-below") {
69+
return (
70+
<SimpleTooltip
71+
button={
72+
<span
73+
onClick={(e) => {
74+
e.stopPropagation();
75+
copy();
76+
}}
77+
className={cn(
78+
"cursor-pointer text-text-bright transition-colors hover:text-white",
79+
className
80+
)}
81+
>
82+
{value}
83+
</span>
84+
}
85+
content={copied ? "Copied" : "Click to copy"}
86+
className="font-sans px-2 py-1"
87+
disableHoverableContent
88+
open={isHovered || copied}
89+
onOpenChange={setIsHovered}
90+
/>
91+
);
92+
}
93+
94+
return null;
6195
}

apps/webapp/app/components/primitives/Tooltip.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { cn } from "~/utils/cn";
66
const variantClasses = {
77
basic:
88
"bg-background-bright border border-grid-bright rounded px-3 py-2 text-sm text-text-bright shadow-md fade-in-50",
9-
dark: "bg-background-dimmed border border-grid-bright rounded px-3 py-2 text-sm text-text-bright shadow-md fade-in-50",
9+
dark: "bg-background-dimmed border border-grid-bright rounded px-3 py-2 text-sm text-text-bright shadow-md fade-in-50"
1010
};
1111

1212
type Variant = keyof typeof variantClasses;
@@ -64,6 +64,8 @@ function SimpleTooltip({
6464
buttonStyle,
6565
asChild = false,
6666
sideOffset,
67+
open,
68+
onOpenChange,
6769
}: {
6870
button: React.ReactNode;
6971
content: React.ReactNode;
@@ -76,10 +78,12 @@ function SimpleTooltip({
7678
buttonStyle?: React.CSSProperties;
7779
asChild?: boolean;
7880
sideOffset?: number;
81+
open?: boolean;
82+
onOpenChange?: (open: boolean) => void;
7983
}) {
8084
return (
8185
<TooltipProvider disableHoverableContent={disableHoverableContent}>
82-
<Tooltip>
86+
<Tooltip open={open} onOpenChange={onOpenChange}>
8387
<TooltipTrigger
8488
tabIndex={-1}
8589
className={cn("h-fit", buttonClassName)}

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ export default function Page() {
205205
to: v3RunsPath(organization, project, environment, filters),
206206
text: "Runs",
207207
}}
208-
title={<CopyableText value={run.friendlyId} />}
208+
title={<CopyableText value={run.friendlyId} variant="text-below"/>}
209209
/>
210210
{environment.type === "DEVELOPMENT" && <DevDisconnectedBanner isConnected={isConnected} />}
211211
<PageAccessories>

0 commit comments

Comments
 (0)