Add export method dialog, extract shared Dialog primitive

Add export dialog with download/clipboard options and optional
undo/redo history inclusion (default off). Extract shared Dialog
component to ui/dialog.tsx, consolidating open/close lifecycle,
backdrop click, and escape key handling from all 6 dialog components.
Update spec to reflect export method dialog and optional history.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lukas
2026-03-27 14:57:31 +01:00
parent 4969ed069b
commit 209df13c32
10 changed files with 218 additions and 193 deletions

View File

@@ -0,0 +1,94 @@
import { Check, ClipboardCopy, Download, X } from "lucide-react";
import { useCallback, useState } from "react";
import { Button } from "./ui/button.js";
import { Dialog } from "./ui/dialog.js";
interface ExportMethodDialogProps {
open: boolean;
onDownload: (includeHistory: boolean) => void;
onCopyToClipboard: (includeHistory: boolean) => void;
onClose: () => void;
}
export function ExportMethodDialog({
open,
onDownload,
onCopyToClipboard,
onClose,
}: Readonly<ExportMethodDialogProps>) {
const [includeHistory, setIncludeHistory] = useState(false);
const [copied, setCopied] = useState(false);
const handleClose = useCallback(() => {
setIncludeHistory(false);
setCopied(false);
onClose();
}, [onClose]);
return (
<Dialog open={open} onClose={handleClose} className="w-80">
<div className="mb-4 flex items-center justify-between">
<h2 className="font-semibold text-lg">Export Encounter</h2>
<Button
type="button"
variant="ghost"
size="icon-sm"
onClick={handleClose}
className="text-muted-foreground"
>
<X className="h-4 w-4" />
</Button>
</div>
<label className="mb-4 flex items-center gap-2 text-sm">
<input
type="checkbox"
checked={includeHistory}
onChange={(e) => setIncludeHistory(e.target.checked)}
className="accent-accent"
/>
<span className="text-foreground">Include undo/redo history</span>
</label>
<div className="flex flex-col gap-2">
<button
type="button"
className="flex items-center gap-3 rounded-lg border border-border px-4 py-3 text-left text-foreground text-sm hover:bg-hover-neutral-bg"
onClick={() => {
onDownload(includeHistory);
handleClose();
}}
>
<Download className="h-5 w-5 text-muted-foreground" />
<div>
<div className="font-medium">Download file</div>
<div className="text-muted-foreground text-xs">
Save as a JSON file
</div>
</div>
</button>
<button
type="button"
className="flex items-center gap-3 rounded-lg border border-border px-4 py-3 text-left text-foreground text-sm hover:bg-hover-neutral-bg"
onClick={() => {
onCopyToClipboard(includeHistory);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}}
>
{copied ? (
<Check className="h-5 w-5 text-green-400" />
) : (
<ClipboardCopy className="h-5 w-5 text-muted-foreground" />
)}
<div>
<div className="font-medium">
{copied ? "Copied!" : "Copy to clipboard"}
</div>
<div className="text-muted-foreground text-xs">
Copy JSON to your clipboard
</div>
</div>
</button>
</div>
</Dialog>
);
}