diff --git a/src/components/ui/index.ts b/src/components/ui/index.ts index 10bad1cdfd..98d21513be 100644 --- a/src/components/ui/index.ts +++ b/src/components/ui/index.ts @@ -15,3 +15,4 @@ export * from './sonner'; export * from './switch'; export * from './table'; export * from './tabs'; +export * from './tooltip'; diff --git a/src/components/ui/tooltip.tsx b/src/components/ui/tooltip.tsx new file mode 100644 index 0000000000..338e7f8d73 --- /dev/null +++ b/src/components/ui/tooltip.tsx @@ -0,0 +1,30 @@ +'use client'; + +import * as React from 'react'; +import * as TooltipPrimitive from '@radix-ui/react-tooltip'; + +import { cn } from '@/lib/utils'; + +const TooltipProvider = TooltipPrimitive.Provider; + +const Tooltip = TooltipPrimitive.Root; + +const TooltipTrigger = TooltipPrimitive.Trigger; + +const TooltipContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + +)); +TooltipContent.displayName = TooltipPrimitive.Content.displayName; + +export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; diff --git a/src/components/usage/TaskCard.tsx b/src/components/usage/TaskCard.tsx index 57ce1dafac..746085ff60 100644 --- a/src/components/usage/TaskCard.tsx +++ b/src/components/usage/TaskCard.tsx @@ -1,6 +1,18 @@ -import { formatNumber, formatCurrency } from '@/lib/formatters'; +import { + formatNumber, + formatCurrency, + formatTimestamp, +} from '@/lib/formatters'; import { generateFallbackTitle } from '@/lib/taskUtils'; -import { Card, CardContent, Button } from '@/components/ui'; +import { + Card, + CardContent, + Button, + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from '@/components/ui'; import type { TaskWithUser } from '@/actions/analytics'; import type { Filter } from '@/app/(authenticated)/usage/types'; @@ -35,66 +47,75 @@ const formatElegantTime = (timestamp: number): string => { export const TaskCard = ({ task, onFilter, onTaskSelected }: TaskCardProps) => { return ( - onTaskSelected(task)} - > - -
- {/* Line 1: Title and Status */} -
-

- {task.title || generateFallbackTitle(task)} -

- -
- - {/* Line 2: All metadata in a single line with bullet separators between items */} -
- {/* Left side: Date, User, and Mode (if present) with bullet separators */} -
- - {formatElegantTime(task.timestamp)} - -
- - - {/* Mode (if present) */} - {task.mode && ( - <> -
- - {task.mode} - - - )} + + onTaskSelected(task)} + > + +
+ {/* Line 1: Title and Status */} +
+

+ {task.title || generateFallbackTitle(task)} +

+
- {/* Right side: Tokens and Cost with bullet separator */} -
- - {formatNumber(task.tokens)} tokens - -
- {formatCurrency(task.cost)} + {/* Line 2: All metadata in a single line with bullet separators between items */} +
+ {/* Left side: Date, User, and Mode (if present) with bullet separators */} +
+ + + + {formatElegantTime(task.timestamp)} + + + +

{formatTimestamp(task.timestamp)}

+
+
+
+ + + {/* Mode (if present) */} + {task.mode && ( + <> +
+ + {task.mode} + + + )} +
+ + {/* Right side: Tokens and Cost with bullet separator */} +
+ + {formatNumber(task.tokens)} tokens + +
+ {formatCurrency(task.cost)} +
-
-
-
+ + +
); };