Files
Codewalkers/apps/web/src/components/review/LineWithComments.tsx
Lukas May 34578d39c6 refactor: Restructure monorepo to apps/server/ and apps/web/ layout
Move src/ → apps/server/ and packages/web/ → apps/web/ to adopt
standard monorepo conventions (apps/ for runnable apps, packages/
for reusable libraries). Update all config files, shared package
imports, test fixtures, and documentation to reflect new paths.

Key fixes:
- Update workspace config to ["apps/*", "packages/*"]
- Update tsconfig.json rootDir/include for apps/server/
- Add apps/web/** to vitest exclude list
- Update drizzle.config.ts schema path
- Fix ensure-schema.ts migration path detection (3 levels up in dev,
  2 levels up in dist)
- Fix tests/integration/cli-server.test.ts import paths
- Update packages/shared imports to apps/server/ paths
- Update all docs/ files with new paths
2026-03-03 11:22:53 +01:00

139 lines
3.8 KiB
TypeScript

import { useRef, useEffect } from "react";
import { MessageSquarePlus } from "lucide-react";
import type { DiffLine, ReviewComment } from "./types";
import { CommentThread } from "./CommentThread";
import { CommentForm } from "./CommentForm";
interface LineWithCommentsProps {
line: DiffLine;
lineKey: number;
lineComments: ReviewComment[];
isCommenting: boolean;
onStartComment: () => void;
onCancelComment: () => void;
onSubmitComment: (body: string) => void;
onResolveComment: (commentId: string) => void;
onUnresolveComment: (commentId: string) => void;
}
export function LineWithComments({
line,
lineKey,
lineComments,
isCommenting,
onStartComment,
onCancelComment,
onSubmitComment,
onResolveComment,
onUnresolveComment,
}: LineWithCommentsProps) {
const formRef = useRef<HTMLTextAreaElement>(null);
useEffect(() => {
if (isCommenting) {
formRef.current?.focus();
}
}, [isCommenting]);
const bgClass =
line.type === "added"
? "bg-green-50 dark:bg-green-950/20"
: line.type === "removed"
? "bg-red-50 dark:bg-red-950/20"
: "";
const gutterBgClass =
line.type === "added"
? "bg-green-100 dark:bg-green-950/40"
: line.type === "removed"
? "bg-red-100 dark:bg-red-950/40"
: "bg-muted/30";
const prefix =
line.type === "added" ? "+" : line.type === "removed" ? "-" : " ";
const textColorClass =
line.type === "added"
? "text-green-800 dark:text-green-300"
: line.type === "removed"
? "text-red-800 dark:text-red-300"
: "";
return (
<>
<tr
className={`group ${bgClass} hover:brightness-95 dark:hover:brightness-110`}
>
{/* Line numbers */}
<td
className={`w-[72px] min-w-[72px] select-none text-right text-muted-foreground pr-1 ${gutterBgClass} align-top`}
>
<div className="flex items-center justify-end gap-0">
<span className="w-8 inline-block text-right text-[11px] leading-5">
{line.oldLineNumber ?? ""}
</span>
<span className="w-8 inline-block text-right text-[11px] leading-5">
{line.newLineNumber ?? ""}
</span>
</div>
</td>
{/* Comment button gutter */}
<td className={`w-6 min-w-6 ${gutterBgClass} align-top`}>
<button
className="opacity-0 group-hover:opacity-100 transition-opacity p-0.5 hover:text-blue-600"
onClick={onStartComment}
title="Add comment"
>
<MessageSquarePlus className="h-3.5 w-3.5" />
</button>
</td>
{/* Code content */}
<td className="pl-1 pr-3 align-top">
<pre
className={`leading-5 whitespace-pre-wrap break-all ${textColorClass}`}
>
<span className="select-none text-muted-foreground/60">
{prefix}
</span>
{line.content}
</pre>
</td>
</tr>
{/* Existing comments on this line */}
{lineComments.length > 0 && (
<tr>
<td
colSpan={3}
className="px-3 py-2 bg-muted/20 border-y border-border/50"
>
<CommentThread
comments={lineComments}
onResolve={onResolveComment}
onUnresolve={onUnresolveComment}
/>
</td>
</tr>
)}
{/* Inline comment form */}
{isCommenting && (
<tr>
<td
colSpan={3}
className="px-3 py-2 bg-blue-50/50 dark:bg-blue-950/20 border-y border-blue-200 dark:border-blue-900"
>
<CommentForm
ref={formRef}
onSubmit={onSubmitComment}
onCancel={onCancelComment}
/>
</td>
</tr>
)}
</>
);
}