components/annotations.tsx (55 lines of code) (raw):
import { ExternalLinkIcon } from "lucide-react";
export type Annotation = {
type: "file_citation" | "url_citation";
fileId?: string;
url?: string;
title?: string;
filename?: string;
index?: number;
};
const AnnotationPill = ({ annotation }: { annotation: Annotation }) => {
const className =
"inline-block text-nowrap px-3 py-1 rounded-full text-xs max-w-48 shrink-0 text-ellipsis overflow-hidden bg-[#ededed] text-zinc-500";
switch (annotation.type) {
case "file_citation":
return <span className={className}>{annotation.filename}</span>;
case "url_citation":
return (
<a
target="_blank"
rel="noopener noreferrer"
href={annotation.url}
className={className}
>
<div className=" flex items-center gap-1">
<div className="truncate">{annotation.title}</div>
<ExternalLinkIcon size={12} className="shrink-0" />
</div>
</a>
);
}
};
const Annotations = ({ annotations }: { annotations: Annotation[] }) => {
const uniqueAnnotations = annotations.reduce(
(acc: Annotation[], annotation) => {
if (
!acc.some(
(a: Annotation) =>
a.type === annotation.type &&
((annotation.type === "file_citation" &&
a.fileId === annotation.fileId) ||
(annotation.type === "url_citation" && a.url === annotation.url))
)
) {
acc.push(annotation);
}
return acc;
},
[]
);
return (
<div className="flex max-w-full mr-28 ml-4 overflow-x-scroll gap-2 mb-2">
{uniqueAnnotations.map((annotation: Annotation, index: number) => (
<AnnotationPill key={index} annotation={annotation} />
))}
</div>
);
};
export default Annotations;