Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 42 additions & 10 deletions apps/web/src/components/ui/toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@ import { useEffect, type CSSProperties } from "react";
import { useParams } from "@tanstack/react-router";
import { ThreadId } from "@t3tools/contracts";
import {
CheckIcon,
CircleAlertIcon,
CircleCheckIcon,
CopyIcon,
InfoIcon,
LoaderCircleIcon,
TriangleAlertIcon,
} from "lucide-react";

import { cn } from "~/lib/utils";
import { buttonVariants } from "~/components/ui/button";
import { useCopyToClipboard } from "~/hooks/useCopyToClipboard";
import { buildVisibleToastLayout, shouldHideCollapsedToastContent } from "./toast.logic";

type ThreadToastData = {
Expand All @@ -35,6 +38,25 @@ const TOAST_ICONS = {
warning: TriangleAlertIcon,
} as const;

function CopyErrorButton({ text }: { text: string }) {
const { copyToClipboard, isCopied } = useCopyToClipboard();

return (
<button
className="shrink-0 cursor-pointer rounded-md p-1 text-muted-foreground opacity-60 transition-opacity hover:opacity-100"
onClick={() => copyToClipboard(text)}
title="Copy error"
type="button"
>
{isCopied ? (
<CheckIcon className="size-3.5 text-success" />
) : (
<CopyIcon className="size-3.5" />
)}
</button>
);
}

type ToastPosition =
| "top-left"
| "top-center"
Expand Down Expand Up @@ -284,12 +306,17 @@ function Toasts({ position = "top-right" }: { position: ToastPosition }) {
)}

<div className="flex min-w-0 flex-1 flex-col gap-0.5">
<Toast.Title
className="min-w-0 break-words font-medium"
data-slot="toast-title"
/>
<div className="flex items-center justify-between gap-1">
<Toast.Title
className="min-w-0 break-words font-medium"
data-slot="toast-title"
/>
{toast.type === "error" && typeof toast.description === "string" && (
<CopyErrorButton text={toast.description} />
)}
</div>
<Toast.Description
className="min-w-0 break-words text-muted-foreground"
className="min-w-0 select-text break-words text-muted-foreground"
data-slot="toast-description"
/>
</div>
Expand Down Expand Up @@ -373,12 +400,17 @@ function AnchoredToasts() {
)}

<div className="flex min-w-0 flex-1 flex-col gap-0.5">
<Toast.Title
className="min-w-0 break-words font-medium"
data-slot="toast-title"
/>
<div className="flex items-center gap-1">
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent justify-between in anchored toast title row

Low Severity

The title-row wrapper in Toasts uses justify-between to push the CopyErrorButton to the far right, but the equivalent wrapper in AnchoredToasts omits it. This causes the copy button to render immediately adjacent to the title text in anchored toasts instead of being right-aligned, resulting in inconsistent placement between the two toast layouts.

Additional Locations (1)
Fix in Cursor Fix in Web

<Toast.Title
className="min-w-0 break-words font-medium"
data-slot="toast-title"
/>
{toast.type === "error" && typeof toast.description === "string" && (
<CopyErrorButton text={toast.description} />
)}
</div>
<Toast.Description
className="min-w-0 break-words text-muted-foreground"
className="min-w-0 select-text break-words text-muted-foreground"
data-slot="toast-description"
/>
</div>
Expand Down