1import { scopeProjectRef, scopeThreadRef } from "@t3tools/client-runtime/environment";
2import type { EnvironmentId, ThreadId } from "@t3tools/contracts";
3import { formatThreadLink, percentDecodedThreadLinkId } from "@t3tools/shared/threadLinks";
4import { Link } from "@tanstack/react-router";
5import { MessageSquareTextIcon } from "lucide-react";
6
7import { useProject, useThreadShell } from "../../state/entities";
8import { ProjectFavicon } from "../ProjectFavicon";
9
10/**
11 * A `t3-thread://` link in chat. It shows the thread's current title, so a rename
12 * reaches every message that links to it, and leads with the thread's project icon
13 * the way a web link leads with its favicon. `label` is what the message wrote,
14 * shown only when this client cannot see the thread. Opens the thread in the app.
15 */
16export function MarkdownThreadLink(props: {
17 readonly environmentId: EnvironmentId;
18 readonly threadId: ThreadId;
19 readonly label: string;
20}) {
21 const decodedId = percentDecodedThreadLinkId(props.threadId);
22 const written = useThreadShell(scopeThreadRef(props.environmentId, props.threadId));
23 const decoded = useThreadShell(
24 written === null && decodedId !== null ? scopeThreadRef(props.environmentId, decodedId) : null,
25 );
26 const thread = written ?? decoded;
27 const threadId = thread?.id ?? props.threadId;
28 const project = useProject(
29 thread === null ? null : scopeProjectRef(props.environmentId, thread.projectId),
30 );
31 const title = thread?.title.trim() || props.label;
32 return (
33 <Link
34 to="/$environmentId/$threadId"
35 params={{ environmentId: props.environmentId, threadId }}
36 // Like an attached thread chip: archived threads are not in the index but still open.
37 title={thread === null ? "Thread no longer available" : project?.title}
38 data-markdown-copy={formatThreadLink(threadId, title)}
39 >
40 <span
41 className="ms-[0.25em] me-[0.2em] inline-flex size-[14px] [vertical-align:-0.125em]"
42 aria-hidden
43 >
44 {project === null ? (
45 <MessageSquareTextIcon className="block size-full shrink-0" />
46 ) : (
47 <ProjectFavicon project={project} className="size-full" />
48 )}
49 </span>
50 {title}
51 </Link>
52 );
53}