Elements

42 / 122 · Knowledge

Document reference

A document the answer leans on, with the quoted passage and the page to jump to.

migration-0.14.pdf14 pages · 2 cited

Installation

npx shadcn@latest add "@assistant-ui/elements-document-reference"

Usage

import { DocumentReference } from "@/components/elements/document-reference";

<DocumentReference
  title="migration-0.14.pdf"
  pages={14}
  anchors={anchors}
  activePage={4}
  onJump={setPage}
/>

Props

title*stringDocument name.
pages*numberTotal page count.
anchors*DocumentAnchor[]The passages the answer drew on, each pinned to a page.
activePage*numberWhich anchor is highlighted.
onJump(page: number) => voidCalled with the page to open.
classNamestringExtra classes merged onto the root.

Source

document-reference.tsx
"use client";

import { FileTextIcon } from "lucide-react";
import { cn } from "@/lib/utils";
import { field, mono, paper } from "./surfaces";

export interface DocumentAnchor {
  page: number;
  quote: string;
}

export function DocumentReference({
  title,
  pages,
  anchors,
  activePage,
  onJump,
  className,
}: {
  title: string;
  pages: number;
  anchors: readonly DocumentAnchor[];
  activePage: number;
  onJump?: (page: number) => void;
  className?: string;
}) {
  return (
    <div
      className={cn(
        paper,
        "flex w-full max-w-sm flex-col gap-3 rounded-2xl p-3.5",
        className,
      )}
    >
      <div className="flex items-center gap-2.5">
        <span className="bg-foreground/[0.05] text-foreground/45 flex size-8 shrink-0 items-center justify-center rounded-lg">
          <FileTextIcon className="size-3.5" />
        </span>
        <div className="flex min-w-0 flex-1 flex-col">
          <span className="truncate text-[13.5px] font-medium">{title}</span>
          <span className={cn(mono, "text-foreground/30")}>
            {pages} pages · {anchors.length} cited
          </span>
        </div>
      </div>

      <div className="flex flex-col gap-1.5">
        {anchors.map((anchor, i) => (
          <button
            key={`${anchor.page}-${i}`}
            type="button"
            onClick={() => onJump?.(anchor.page)}
            className={cn(
              "flex flex-col gap-1 rounded-xl px-2.5 py-2 text-start transition-colors",
              anchor.page === activePage
                ? field
                : "hover:bg-foreground/[0.035]",
            )}
          >
            <span className={cn(mono, "text-foreground/30")}>
              p. {anchor.page}
            </span>
            <span className="text-foreground/65 border-foreground/15 border-s-2 ps-2 text-xs leading-relaxed">
              {anchor.quote}
            </span>
          </button>
        ))}
      </div>
    </div>
  );
}