Files
Codewalkers/apps/web/src/components/review/HunkRows.tsx
Lukas May 04c212da92 feat: Implement v2 design system with indigo brand, dark mode, and status tokens
Complete frontend design overhaul replacing achromatic shadcn/ui defaults with
an indigo-branded (#6366F1), status-aware, dark-mode-enabled token system.

Phase 1 — Theme Foundation:
- Replace all CSS tokens in index.css with v2 light/dark mode values
- Add 24 status tokens (6 statuses × 4 variants), 22 terminal tokens,
  7 diff tokens, 5 shadow tokens, 9 transition/animation tokens,
  10 z-index tokens, 10-step extended indigo scale
- Install Geist Sans/Mono variable fonts (public/fonts/)
- Extend tailwind.config.ts with all new token utilities
- Add dark mode flash-prevention script in index.html
- Add status-pulse and shimmer keyframe animations
- Add global focus-visible styles and reduced-motion media query

Phase 2 — ThemeProvider + Toggle:
- ThemeProvider context with system preference listener
- 3-state ThemeToggle (Sun/Monitor/Moon)
- Radix tooltip primitive for tooltips
- localStorage persistence with 'cw-theme' key

Phase 3 — Shared Components + Token Migration:
- StatusDot: mapEntityStatus() maps raw statuses to 6 semantic variants
- StatusBadge: uses status token bg/fg/border classes
- Badge: 6 new status variants + xs size
- EmptyState, ErrorState, SaveIndicator shared patterns
- CommandPalette: Cmd+K search with fuzzy matching, keyboard nav
- Skeleton with shimmer animation + SkeletonCard composite layouts
- KeyboardShortcutHint, NavBadge, enhanced Sonner config
- Migrate ALL hardcoded Tailwind colors to token classes across
  AgentOutputViewer, review/*, ProgressBar, AccountCard,
  InitiativeHeader, DependencyIndicator, PipelineTaskCard,
  PreviewPanel, ChangeSetBanner, MessageCard, PhaseDetailPanel

Phase 4 — App Layout Overhaul:
- Single 48px row header with CW logo, nav with NavBadge counts,
  Cmd+K search button, ThemeToggle, HealthDot
- Remove max-w-7xl from header/main; pages control own widths
- ConnectionBanner for offline/reconnecting states
- BrowserTitleUpdater with running/questions counts
- useGlobalKeyboard (1-4 nav, Cmd+K), useConnectionStatus hooks
- Per-page width wrappers (initiatives max-w-6xl, settings max-w-4xl)

Phase 5 — Page-Level Token Migration:
- ReviewSidebar: all hardcoded green/orange/red → status/diff tokens
- CommentThread: resolved state → status-success tokens
- Settings health: green → status-success-dot
2026-03-03 11:43:09 +01:00

87 lines
2.3 KiB
TypeScript

import { useState, useCallback } from "react";
import type { DiffLine, ReviewComment } from "./types";
import { LineWithComments } from "./LineWithComments";
interface HunkRowsProps {
hunk: { header: string; lines: DiffLine[] };
filePath: string;
comments: ReviewComment[];
onAddComment: (
filePath: string,
lineNumber: number,
lineType: DiffLine["type"],
body: string,
) => void;
onResolveComment: (commentId: string) => void;
onUnresolveComment: (commentId: string) => void;
}
export function HunkRows({
hunk,
filePath,
comments,
onAddComment,
onResolveComment,
onUnresolveComment,
}: HunkRowsProps) {
const [commentingLine, setCommentingLine] = useState<{
lineNumber: number;
lineType: DiffLine["type"];
} | null>(null);
const handleSubmitComment = useCallback(
(body: string) => {
if (!commentingLine) return;
onAddComment(
filePath,
commentingLine.lineNumber,
commentingLine.lineType,
body,
);
setCommentingLine(null);
},
[commentingLine, filePath, onAddComment],
);
return (
<>
{/* Hunk header */}
<tr>
<td
colSpan={3}
className="px-3 py-1 text-muted-foreground bg-diff-hunk-bg text-[11px] select-none"
>
{hunk.header}
</td>
</tr>
{hunk.lines.map((line, li) => {
const lineKey = line.newLineNumber ?? line.oldLineNumber ?? li;
const lineComments = comments.filter(
(c) => c.lineNumber === lineKey && c.lineType === line.type,
);
const isCommenting =
commentingLine?.lineNumber === lineKey &&
commentingLine?.lineType === line.type;
return (
<LineWithComments
key={`${line.type}-${lineKey}-${li}`}
line={line}
lineKey={lineKey}
lineComments={lineComments}
isCommenting={isCommenting}
onStartComment={() =>
setCommentingLine({ lineNumber: lineKey, lineType: line.type })
}
onCancelComment={() => setCommentingLine(null)}
onSubmitComment={handleSubmitComment}
onResolveComment={onResolveComment}
onUnresolveComment={onUnresolveComment}
/>
);
})}
</>
);
}