1import type { PullRequestReviewGuideNote } from "@t3tools/contracts";
2
3import { cn } from "~/lib/utils";
4
5import { GuideProse } from "./GuideProse";
6
7/** The letter that ties a note to its line in an excerpt. */
8export function GuideNoteMarker({ marker }: { marker: string }) {
9 return (
10 <span
11 aria-hidden
12 className="inline-flex size-4.5 shrink-0 items-center justify-center rounded-full bg-info/16 font-medium text-3xs text-info-foreground tabular-nums"
13 >
14 {marker}
15 </span>
16 );
17}
18
19/** A stop's notes, lettered in the order the excerpts mark them. */
20export function GuideNotes({
21 notes,
22 className,
23}: {
24 notes: ReadonlyArray<{ readonly marker: string; readonly note: PullRequestReviewGuideNote }>;
25 className?: string;
26}) {
27 if (notes.length === 0) return null;
28 return (
29 <section className={cn("flex min-w-0 flex-col gap-2", className)}>
30 <h4 className="flex items-baseline justify-between gap-2 text-xs font-medium text-foreground">
31 Notes on this stop
32 <span className="font-normal text-muted-foreground tabular-nums">
33 {notes.length === 1 ? "1 note" : `${notes.length} notes`}
34 </span>
35 </h4>
36 <ol className="flex flex-col gap-3">
37 {notes.map(({ marker, note }) => (
38 <li key={marker} className="flex min-w-0 gap-2">
39 <GuideNoteMarker marker={marker} />
40 <div className="flex min-w-0 flex-col gap-0.5">
41 <p className="flex flex-wrap items-baseline gap-x-2 text-xs">
42 <span className="font-medium text-foreground">{note.title}</span>
43 <span className="truncate font-mono text-2xs text-muted-foreground">
44 {note.path.split("/").at(-1)}:{note.line}
45 </span>
46 </p>
47 {note.body.trim() !== "" ? (
48 <div className="text-xs text-muted-foreground">
49 <GuideProse text={note.body} />
50 </div>
51 ) : null}
52 </div>
53 </li>
54 ))}
55 </ol>
56 </section>
57 );
58}