refactor: enhance UI components for consistency and user experience

- Updated various card components across Google Drive, Linear, and Notion tools to include the `select-none` class for improved user interaction by preventing text selection.
- Ensured consistent styling and behavior in loading states and error handling across different tool UIs, enhancing overall usability and visual coherence.
This commit is contained in:
Anish Sarkar 2026-03-20 17:51:11 +05:30
parent 8850fac722
commit 151dcd26e1
8 changed files with 46 additions and 46 deletions

View file

@ -467,7 +467,7 @@ function InsufficientPermissionsCard({ result }: { result: InsufficientPermissio
function ErrorCard({ result }: { result: ErrorResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-destructive">Failed to create Google Drive file</p>
</div>
@ -481,7 +481,7 @@ function ErrorCard({ result }: { result: ErrorResult }) {
function AuthErrorCard({ result }: { result: AuthErrorResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-destructive">
Google Drive authentication expired
@ -497,7 +497,7 @@ function AuthErrorCard({ result }: { result: AuthErrorResult }) {
function SuccessCard({ result }: { result: SuccessResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-foreground">
{result.message || "Google Drive file created successfully"}
@ -534,7 +534,7 @@ export const CreateGoogleDriveFileToolUI = makeAssistantToolUI<
render: function CreateGoogleDriveFileUI({ args, result, status }) {
if (status.type === "running") {
return (
<div className="my-4 max-w-lg rounded-2xl border bg-muted/30 px-5 py-4">
<div className="my-4 max-w-lg rounded-2xl border bg-muted/30 px-5 py-4 select-none">
<TextShimmerLoader text="Preparing Google Drive file..." size="sm" />
</div>
);

View file

@ -380,7 +380,7 @@ function InsufficientPermissionsCard({ result }: { result: InsufficientPermissio
function AuthErrorCard({ result }: { result: AuthErrorResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-destructive">
Google Drive authentication expired
@ -396,7 +396,7 @@ function AuthErrorCard({ result }: { result: AuthErrorResult }) {
function WarningCard({ result }: { result: WarningResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="flex items-start gap-3 border-b px-5 py-4">
<TriangleAlertIcon className="size-4 mt-0.5 shrink-0 text-amber-500" />
<p className="text-sm font-medium text-amber-600 dark:text-amber-500">Partial success</p>
@ -411,7 +411,7 @@ function WarningCard({ result }: { result: WarningResult }) {
function ErrorCard({ result }: { result: ErrorResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-destructive">Failed to delete file</p>
</div>
@ -425,7 +425,7 @@ function ErrorCard({ result }: { result: ErrorResult }) {
function NotFoundCard({ result }: { result: NotFoundResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="flex items-start gap-3 px-5 py-4">
<InfoIcon className="size-4 mt-0.5 shrink-0 text-muted-foreground" />
<p className="text-sm text-muted-foreground">{result.message}</p>
@ -436,7 +436,7 @@ function NotFoundCard({ result }: { result: NotFoundResult }) {
function SuccessCard({ result }: { result: SuccessResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-foreground">
{result.message || "File moved to trash successfully"}
@ -464,7 +464,7 @@ export const DeleteGoogleDriveFileToolUI = makeAssistantToolUI<
render: function DeleteGoogleDriveFileUI({ result, status }) {
if (status.type === "running") {
return (
<div className="my-4 max-w-lg rounded-2xl border bg-muted/30 px-5 py-4">
<div className="my-4 max-w-lg rounded-2xl border bg-muted/30 px-5 py-4 select-none">
<TextShimmerLoader text="Looking up file in Google Drive..." size="sm" />
</div>
);

View file

@ -515,7 +515,7 @@ function ApprovalCard({
function AuthErrorCard({ result }: { result: AuthErrorResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-destructive">
All Linear accounts expired
@ -531,7 +531,7 @@ function AuthErrorCard({ result }: { result: AuthErrorResult }) {
function ErrorCard({ result }: { result: ErrorResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-destructive">Failed to create Linear issue</p>
</div>
@ -545,7 +545,7 @@ function ErrorCard({ result }: { result: ErrorResult }) {
function SuccessCard({ result }: { result: SuccessResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-foreground">
{result.message || "Linear issue created successfully"}
@ -582,9 +582,9 @@ export const CreateLinearIssueToolUI = makeAssistantToolUI<
render: function CreateLinearIssueUI({ args, result, status }) {
if (status.type === "running") {
return (
<div className="my-4 max-w-lg rounded-2xl border bg-muted/30 px-5 py-4">
<TextShimmerLoader text="Preparing Linear issue..." size="sm" />
</div>
<div className="my-4 max-w-lg rounded-2xl border bg-muted/30 px-5 py-4 select-none">
<TextShimmerLoader text="Preparing Linear issue..." size="sm" />
</div>
);
}

View file

@ -282,7 +282,7 @@ function ApprovalCard({
function AuthErrorCard({ result }: { result: AuthErrorResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-destructive">
Linear authentication expired
@ -298,7 +298,7 @@ function AuthErrorCard({ result }: { result: AuthErrorResult }) {
function ErrorCard({ result }: { result: ErrorResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-destructive">Failed to delete Linear issue</p>
</div>
@ -312,7 +312,7 @@ function ErrorCard({ result }: { result: ErrorResult }) {
function NotFoundCard({ result }: { result: NotFoundResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-amber-600 dark:text-amber-400">
Issue not found
@ -328,7 +328,7 @@ function NotFoundCard({ result }: { result: NotFoundResult }) {
function WarningCard({ result }: { result: WarningResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="flex items-start gap-3 border-b px-5 py-4">
<TriangleAlertIcon className="size-4 mt-0.5 shrink-0 text-amber-500" />
<p className="text-sm font-medium text-amber-600 dark:text-amber-500">Partial success</p>
@ -342,7 +342,7 @@ function WarningCard({ result }: { result: WarningResult }) {
function SuccessCard({ result }: { result: SuccessResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-foreground">
{result.message || "Linear issue archived successfully"}
@ -370,9 +370,9 @@ export const DeleteLinearIssueToolUI = makeAssistantToolUI<
render: function DeleteLinearIssueUI({ result, status }) {
if (status.type === "running") {
return (
<div className="my-4 max-w-lg rounded-2xl border bg-muted/30 px-5 py-4">
<TextShimmerLoader text="Preparing Linear issue deletion..." size="sm" />
</div>
<div className="my-4 max-w-lg rounded-2xl border bg-muted/30 px-5 py-4 select-none">
<TextShimmerLoader text="Preparing Linear issue deletion..." size="sm" />
</div>
);
}

View file

@ -630,7 +630,7 @@ function ApprovalCard({
function AuthErrorCard({ result }: { result: AuthErrorResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-destructive">
Linear authentication expired
@ -646,7 +646,7 @@ function AuthErrorCard({ result }: { result: AuthErrorResult }) {
function ErrorCard({ result }: { result: ErrorResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-destructive">Failed to update Linear issue</p>
</div>
@ -660,7 +660,7 @@ function ErrorCard({ result }: { result: ErrorResult }) {
function NotFoundCard({ result }: { result: NotFoundResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-amber-600 dark:text-amber-400">
Issue not found
@ -676,7 +676,7 @@ function NotFoundCard({ result }: { result: NotFoundResult }) {
function SuccessCard({ result }: { result: SuccessResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-foreground">
{result.message || "Linear issue updated successfully"}
@ -721,9 +721,9 @@ export const UpdateLinearIssueToolUI = makeAssistantToolUI<
render: function UpdateLinearIssueUI({ result, status }) {
if (status.type === "running") {
return (
<div className="my-4 max-w-lg rounded-2xl border bg-muted/30 px-5 py-4">
<TextShimmerLoader text="Preparing Linear issue update..." size="sm" />
</div>
<div className="my-4 max-w-lg rounded-2xl border bg-muted/30 px-5 py-4 select-none">
<TextShimmerLoader text="Preparing Linear issue update..." size="sm" />
</div>
);
}

View file

@ -379,7 +379,7 @@ function ApprovalCard({
function AuthErrorCard({ result }: { result: AuthErrorResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-destructive">
Notion authentication expired
@ -395,7 +395,7 @@ function AuthErrorCard({ result }: { result: AuthErrorResult }) {
function ErrorCard({ result }: { result: ErrorResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-destructive">Failed to create Notion page</p>
</div>
@ -409,7 +409,7 @@ function ErrorCard({ result }: { result: ErrorResult }) {
function SuccessCard({ result }: { result: SuccessResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-foreground">
{result.message || "Notion page created successfully"}
@ -446,7 +446,7 @@ export const CreateNotionPageToolUI = makeAssistantToolUI<
render: function CreateNotionPageUI({ args, result, status }) {
if (status.type === "running") {
return (
<div className="my-4 max-w-lg rounded-2xl border bg-muted/30 px-5 py-4">
<div className="my-4 max-w-lg rounded-2xl border bg-muted/30 px-5 py-4 select-none">
<TextShimmerLoader text="Preparing Notion page..." size="sm" />
</div>
);

View file

@ -282,7 +282,7 @@ function ApprovalCard({
function AuthErrorCard({ result }: { result: AuthErrorResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-destructive">
All Notion accounts expired
@ -298,7 +298,7 @@ function AuthErrorCard({ result }: { result: AuthErrorResult }) {
function ErrorCard({ result }: { result: ErrorResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-destructive">Failed to delete Notion page</p>
</div>
@ -312,7 +312,7 @@ function ErrorCard({ result }: { result: ErrorResult }) {
function InfoCard({ result }: { result: InfoResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-amber-600 dark:text-amber-400">
Page not found
@ -328,7 +328,7 @@ function InfoCard({ result }: { result: InfoResult }) {
function WarningCard({ result }: { result: WarningResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="flex items-start gap-3 border-b px-5 py-4">
<TriangleAlertIcon className="size-4 mt-0.5 shrink-0 text-amber-500" />
<p className="text-sm font-medium text-amber-600 dark:text-amber-500">Partial success</p>
@ -348,7 +348,7 @@ function WarningCard({ result }: { result: WarningResult }) {
function SuccessCard({ result }: { result: SuccessResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-foreground">
{result.message || "Notion page deleted successfully"}
@ -386,7 +386,7 @@ export const DeleteNotionPageToolUI = makeAssistantToolUI<
render: function DeleteNotionPageUI({ result, status }) {
if (status.type === "running") {
return (
<div className="my-4 max-w-lg rounded-2xl border bg-muted/30 px-5 py-4">
<div className="my-4 max-w-lg rounded-2xl border bg-muted/30 px-5 py-4 select-none">
<TextShimmerLoader text="Deleting Notion page..." size="sm" />
</div>
);

View file

@ -309,7 +309,7 @@ function ApprovalCard({
function AuthErrorCard({ result }: { result: AuthErrorResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-destructive">
Notion authentication expired
@ -325,7 +325,7 @@ function AuthErrorCard({ result }: { result: AuthErrorResult }) {
function ErrorCard({ result }: { result: ErrorResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-destructive">Failed to update Notion page</p>
</div>
@ -339,7 +339,7 @@ function ErrorCard({ result }: { result: ErrorResult }) {
function InfoCard({ result }: { result: InfoResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-amber-600 dark:text-amber-400">
Page not found
@ -355,7 +355,7 @@ function InfoCard({ result }: { result: InfoResult }) {
function SuccessCard({ result }: { result: SuccessResult }) {
return (
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30">
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-foreground">
{result.message || "Notion page updated successfully"}
@ -392,7 +392,7 @@ export const UpdateNotionPageToolUI = makeAssistantToolUI<
render: function UpdateNotionPageUI({ args, result, status }) {
if (status.type === "running") {
return (
<div className="my-4 max-w-lg rounded-2xl border bg-muted/30 px-5 py-4">
<div className="my-4 max-w-lg rounded-2xl border bg-muted/30 px-5 py-4 select-none">
<TextShimmerLoader text="Updating Notion page..." size="sm" />
</div>
);