/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ /** * Compare results list + count badges (issue #924), extracted from ComparePanel * to keep it under the module-size house rule (AGENTS.md). */ import { Plus, Minus, PencilLine, MousePointerClick } from 'lucide-react'; import { ScrollArea } from '@/components/ui/scroll-area'; import { cn } from '@/lib/utils'; import { COMPARE_COLORS, type RGBA } from '@/lib/compare/overlay'; import type { DiffState } from '@ifc-lite/diff'; import type { CompareResult } from '@/store/slices/compareSlice'; import type { CompareRow } from './changeRow'; export interface CompareBucket { rows: CompareRow[]; truncated: number; } /** States listed in the panel (unchanged only affects 3D ghosting). */ export const LISTED_STATES: { state: Exclude; label: string; color: RGBA; Icon: typeof Plus }[] = [ { state: 'modified', label: 'Changed', color: COMPARE_COLORS.modified, Icon: PencilLine }, { state: 'added', label: 'Added', color: COMPARE_COLORS.added, Icon: Plus }, { state: 'deleted', label: 'Deleted', color: COMPARE_COLORS.deleted, Icon: Minus }, ]; export function rgbaCss([r, g, b, a]: RGBA): string { return `rgba(${Math.round(r * 255)}, ${Math.round(g * 255)}, ${Math.round(b * 255)}, ${a})`; } export function CountBadge({ label, value, color }: { label: string; value: number; color: RGBA }) { return (
{value.toLocaleString()} {label}
); } interface CompareResultsListProps { result: CompareResult | null; groups: Map; counts: CompareResult['diff']['counts'] | undefined; selectedKey: string | null; onFocus: (row: CompareRow) => void; /** Select every element in a state bucket at once (section-header click). */ onFocusGroup: (state: DiffState) => void; } export function CompareResultsList({ result, groups, counts, selectedKey, onFocus, onFocusGroup }: CompareResultsListProps) { return ( {!result ? (
Run a comparison to see added, changed, and deleted elements.
) : (
{LISTED_STATES.map(({ state, label, color, Icon }) => { const bucket = groups.get(state); if (!bucket || bucket.rows.length === 0) return null; return (
{bucket.rows.map((row) => ( ))} {bucket.truncated > 0 && (

+{bucket.truncated} more not shown

)}
); })} {counts && counts.added + counts.modified + counts.deleted === 0 && (
No differences in scope “{result.scope}”. The models match.
)}
)}
); }