Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

79 linesCodeBlameRaw
1/**
2 * A commit message's text with its references linked: `#12` and
3 * `acme/web#12` to the issue or pull request, with its card on hover, and
4 * a full hash to its commit. Where the whole message links to its commit
5 * (a list of commits), the text between references links there and each
6 * reference links on its own, so no link sits inside another.
7 */
8import type { ReactNode } from "react";
9import { Link } from "react-router";
10
11import { RefCardBody } from "./chat/ref-chip";
12import { HoverCard, HoverCardContent, HoverCardTrigger } from "./ui/hover-card";
13import { cn } from "../lib/cn";
14import { messageParts } from "../lib/commit-message";
15
16/** `#12` in `repo` (`owner/name`): a link to it, its card on hover. */
17export function RefLink({ repo, number, className, children }: { repo: string; number: number; className?: string; children: ReactNode }) {
18 return (
19 <HoverCard>
20 <HoverCardTrigger asChild>
21 {/* Issues and pull requests share numbers; the issue page forwards. */}
22 <Link to={`/${repo}/issues/${number}`} className={cn("relative z-10", className)} data-ref="issue">
23 {children}
24 </Link>
25 </HoverCardTrigger>
26 <HoverCardContent className="w-80">
27 <RefCardBody url={`/${repo}/ref/${number}`} repo={repo} number={number} />
28 </HoverCardContent>
29 </HoverCard>
30 );
31}
32
33/**
34 * `text` with its references linked, in the repository at `base`
35 * (`/owner/name`). With `to`, the text between them links there, styled
36 * by `linkClassName`.
37 */
38export function CommitText({
39 text,
40 base,
41 to,
42 linkClassName,
43 refClassName = "text-accent hover:underline",
44}: {
45 text: string;
46 base: string;
47 to?: string;
48 linkClassName?: string;
49 refClassName?: string;
50}) {
51 const repo = base.replace(/^\//, "");
52 return (
53 <>
54 {messageParts(text).map((part, index) => {
55 if (part.kind === "ref") {
56 return (
57 <RefLink key={index} repo={part.repo ?? repo} number={part.number} className={refClassName}>
58 {part.text}
59 </RefLink>
60 );
61 }
62 if (part.kind === "commit") {
63 return (
64 <Link key={index} to={`${base}/commit/${part.sha}`} className={cn("relative z-10 font-mono text-[0.9em]", refClassName)}>
65 {part.sha.slice(0, 7)}
66 </Link>
67 );
68 }
69 return to ? (
70 <Link key={index} to={to} prefetch="intent" className={linkClassName}>
71 {part.text}
72 </Link>
73 ) : (
74 part.text
75 );
76 })}
77 </>
78 );
79}