Files
kandev/apps/web/components/diff/comment-display.tsx
T
2026-02-02 00:17:23 +00:00

104 lines
3.2 KiB
TypeScript

'use client';
import { Button } from '@kandev/ui/button';
import { IconTrash, IconEdit, IconMessage } from '@tabler/icons-react';
import type { DiffComment } from '@/lib/diff/types';
import { formatLineRange } from '@/lib/diff';
interface CommentDisplayProps {
/** The comment to display */
comment: DiffComment;
/** Callback to delete the comment */
onDelete?: () => void;
/** Callback to edit the comment */
onEdit?: () => void;
/** Whether to show the code content */
showCode?: boolean;
/** Compact mode for inline display */
compact?: boolean;
}
export function CommentDisplay({
comment,
onDelete,
onEdit,
showCode = false,
compact = false,
}: CommentDisplayProps) {
const lineRange = formatLineRange(comment.startLine, comment.endLine);
if (compact) {
return (
<div className="group flex items-start gap-2 rounded border border-border bg-muted/50 px-2 py-1.5 text-xs">
<IconMessage className="mt-0.5 h-3 w-3 shrink-0 text-muted-foreground" />
<div className="min-w-0 flex-1">
<span className="text-muted-foreground">{lineRange}</span>
<span className="mx-1 text-muted-foreground">·</span>
<span className="break-words">{comment.annotation}</span>
</div>
{onDelete && (
<Button
size="sm"
variant="ghost"
onClick={onDelete}
className="h-4 w-4 shrink-0 cursor-pointer p-0 opacity-0 hover:text-destructive group-hover:opacity-100"
>
<IconTrash className="h-3 w-3" />
</Button>
)}
</div>
);
}
return (
<div className="group rounded-md border border-border bg-card p-2 shadow-sm">
{/* Header */}
<div className="mb-1.5 flex items-center justify-between">
<div className="flex items-center gap-1.5 text-xs">
<IconMessage className="h-3.5 w-3.5 text-blue-500" />
<span className="font-medium">
{lineRange}
</span>
<span className="text-muted-foreground">
({comment.side === 'additions' ? 'new' : 'old'})
</span>
</div>
<div className="flex gap-1 opacity-0 transition-opacity group-hover:opacity-100">
{onEdit && (
<Button
size="sm"
variant="ghost"
onClick={onEdit}
className="h-5 w-5 cursor-pointer p-0"
>
<IconEdit className="h-3 w-3" />
</Button>
)}
{onDelete && (
<Button
size="sm"
variant="ghost"
onClick={onDelete}
className="h-5 w-5 cursor-pointer p-0 hover:text-destructive"
>
<IconTrash className="h-3 w-3" />
</Button>
)}
</div>
</div>
{/* Code preview */}
{showCode && comment.codeContent && (
<pre className="mb-2 overflow-x-auto rounded bg-muted p-1.5 text-[10px] leading-tight">
<code>{comment.codeContent}</code>
</pre>
)}
{/* Comment text */}
<p className="whitespace-pre-wrap text-xs leading-relaxed text-foreground">
{comment.annotation}
</p>
</div>
);
}