Add ability to copy references from Web App (#1144)

Add a "Copy References" button to the references pane in the web app.

In ReferencePanel Component
- Add a "Copy References" button to the `ReferencePanel` component.
- Implement functionality to copy all references (notes, online, and
code) as a markdown bullet list.
- Update the `TeaserReferencesSection` component to include the "Copy
References" button.
- Show copied to clipboard indicator when references copied on button click

Closes #1021

---------

Co-authored-by: Debanjum <debanjum@gmail.com>
This commit is contained in:
Koshik Debanath 2026-02-23 01:41:45 +06:00 committed by GitHub
parent 0ba0f3d0f2
commit b0cd8dc8fd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -2,7 +2,7 @@
import { useEffect, useState } from "react";
import { ArrowCircleDown, ArrowRight, Code, Note } from "@phosphor-icons/react";
import { ArrowCircleDown, ArrowRight, Code, Note, Clipboard, Check } from "@phosphor-icons/react";
import markdownIt from "markdown-it";
const md = new markdownIt({
@ -32,6 +32,7 @@ import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover
import DOMPurify from "dompurify";
import { getIconFromFilename } from "@/app/common/iconUtils";
import Link from "next/link";
import { Button } from "@/components/ui/button";
interface NotesContextReferenceData {
title: string;
@ -494,6 +495,18 @@ export function constructAllReferences(
};
}
export function formatReferencesAsMarkdown(
notesReferenceCardData: NotesContextReferenceData[],
onlineReferenceCardData: OnlineReferenceData[],
codeReferenceCardData: CodeReferenceData[],
): string {
return [
...notesReferenceCardData.map((note) => `- ${note.title}`),
...onlineReferenceCardData.map((online) => `- [${online.title}](${online.link})`),
...codeReferenceCardData.map((_, index) => `- Code Reference ${index + 1}`),
].join("\n");
}
interface SimpleIconProps {
type: string;
link?: string;
@ -589,10 +602,20 @@ interface ReferencePanelDataProps {
export default function ReferencePanel(props: ReferencePanelDataProps) {
const [numTeaserSlots, setNumTeaserSlots] = useState(3);
const [copyReferencesSuccess, setCopyReferencesSuccess] = useState(false);
useEffect(() => {
setNumTeaserSlots(props.isMobileWidth ? 3 : 5);
}, [props.isMobileWidth]);
useEffect(() => {
if (copyReferencesSuccess) {
setTimeout(() => {
setCopyReferencesSuccess(false);
}, 1000);
}
}, [copyReferencesSuccess]);
if (!props.notesReferenceCardData && !props.onlineReferenceCardData) {
return null;
}
@ -609,6 +632,17 @@ export default function ReferencePanel(props: ReferencePanelDataProps) {
.slice(0, numTeaserSlots - codeDataToShow.length - notesDataToShow.length)
: [];
const copyReferencesToClipboard = () => {
navigator.clipboard.writeText(
formatReferencesAsMarkdown(
props.notesReferenceCardData,
props.onlineReferenceCardData,
props.codeReferenceCardData,
),
);
setCopyReferencesSuccess(true);
};
return (
<Sheet>
<SheetTrigger className="text-balance w-auto justify-start overflow-hidden break-words p-0 bg-transparent border-none text-gray-400 align-middle items-center m-0 inline-flex">
@ -645,6 +679,23 @@ export default function ReferencePanel(props: ReferencePanelDataProps) {
<SheetHeader>
<SheetTitle>References</SheetTitle>
<SheetDescription>View all references for this response</SheetDescription>
<Button
variant="outline"
onClick={copyReferencesToClipboard}
className="mt-4"
>
{copyReferencesSuccess ? (
<>
<Check className="mr-2 text-green-500" />
Copied!
</>
) : (
<>
<Clipboard className="mr-2" />
Copy References
</>
)}
</Button>
</SheetHeader>
<div className="flex flex-wrap gap-2 w-auto mt-2">
{props.codeReferenceCardData.map((code, index) => {