| import { Icon } from "./Icon"; |
|
|
| type Props = { |
| open: boolean; |
| title?: string; |
| jsonText: string; |
| onClose: () => void; |
| }; |
|
|
| export function PayloadViewerModal({ |
| open, |
| title = "Request payload", |
| jsonText, |
| onClose, |
| }: Props) { |
| if (!open) return null; |
|
|
| const copy = () => { |
| void navigator.clipboard.writeText(jsonText); |
| }; |
|
|
| return ( |
| <div |
| className="fixed inset-0 z-[100] flex items-center justify-center p-4" |
| role="dialog" |
| aria-modal="true" |
| aria-labelledby="payload-modal-title" |
| > |
| <button |
| type="button" |
| className="absolute inset-0 bg-black/40 backdrop-blur-[1px]" |
| aria-label="Close" |
| onClick={onClose} |
| /> |
| <div className="relative flex max-h-[85vh] w-full max-w-3xl flex-col rounded-2xl border border-outline-variant bg-surface-container-lowest shadow-xl"> |
| <div className="flex shrink-0 items-center justify-between gap-3 border-b border-outline-variant px-4 py-3"> |
| <h2 |
| id="payload-modal-title" |
| className="font-headline-md text-base font-bold text-primary" |
| > |
| {title} |
| </h2> |
| <div className="flex items-center gap-2"> |
| <button |
| type="button" |
| onClick={copy} |
| className="flex items-center gap-1.5 rounded-lg border border-outline-variant bg-surface-container-low px-3 py-1.5 text-xs font-semibold text-primary hover:bg-surface-container-high" |
| > |
| <Icon name="content_copy" className="text-sm" /> |
| Copy JSON |
| </button> |
| <button |
| type="button" |
| onClick={onClose} |
| className="rounded-lg p-2 text-secondary hover:bg-surface-container-high hover:text-primary" |
| aria-label="Close" |
| > |
| <Icon name="close" className="text-xl" /> |
| </button> |
| </div> |
| </div> |
| <pre className="min-h-0 flex-1 overflow-auto p-4 font-data-mono text-[11px] leading-relaxed text-primary"> |
| {jsonText} |
| </pre> |
| </div> |
| </div> |
| ); |
| } |
|
|