Files
resolutionflow/frontend/src/components/library/ExportFlowModal.tsx
Michael Chihlas 303a558432 refactor: replace hardcoded hex values with Tailwind semantic tokens
3,200+ hardcoded color values replaced with CSS variable-backed
Tailwind classes (bg-card, text-foreground, border-border, etc.).
Enables light mode via CSS variable swap. Only syntax highlighting
colors and intentional one-offs remain hardcoded (~15 values).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 04:34:35 -04:00

98 lines
3.0 KiB
TypeScript

import { useState, useEffect } from 'react'
import { Download, X } from 'lucide-react'
import { flowTransferApi } from '@/api/flowTransfer'
import { toast } from '@/lib/toast'
import { Button } from '@/components/ui/Button'
interface ExportFlowModalProps {
treeId: string
treeName: string
onClose: () => void
}
function slugify(name: string): string {
return name.toLowerCase().trim().replace(/[^\w\s-]/g, '').replace(/[-\s]+/g, '-')
}
export function ExportFlowModal({ treeId, treeName, onClose }: ExportFlowModalProps) {
const [isExporting, setIsExporting] = useState(false)
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') onClose()
}
document.addEventListener('keydown', handleKeyDown)
return () => document.removeEventListener('keydown', handleKeyDown)
}, [onClose])
const handleExport = async () => {
setIsExporting(true)
try {
const blob = await flowTransferApi.exportFlow(treeId)
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `${slugify(treeName)}.rfflow`
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
URL.revokeObjectURL(url)
toast.success('Flow exported successfully')
onClose()
} catch (err) {
console.error('Export failed:', err)
toast.error('Failed to export flow')
} finally {
setIsExporting(false)
}
}
return (
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4"
onClick={onClose}
>
<div
className="w-full max-w-sm rounded-xl border border-border bg-card shadow-xl"
onClick={(e) => e.stopPropagation()}
>
{/* Header */}
<div className="flex items-center justify-between border-b border-border px-5 py-4">
<div className="flex items-center gap-2">
<Download className="h-4 w-4 text-muted-foreground" />
<h2 className="text-sm font-semibold text-foreground">Export Flow</h2>
</div>
<button
onClick={onClose}
aria-label="Close"
className="rounded-md p-1 text-muted-foreground hover:bg-accent hover:text-foreground"
>
<X className="h-4 w-4" />
</button>
</div>
{/* Body */}
<div className="px-5 py-4">
<p className="text-sm text-muted-foreground">
Export <span className="font-medium text-foreground">{treeName}</span> as a <code className="text-xs font-sans text-xs">.rfflow</code> file (JSON format).
</p>
</div>
{/* Footer */}
<div className="flex justify-end gap-2 border-t border-border px-5 py-3">
<Button variant="secondary" onClick={onClose}>
Cancel
</Button>
<Button
onClick={handleExport}
loading={isExporting}
>
<Download className="h-4 w-4" />
Download .rfflow
</Button>
</div>
</div>
</div>
)
}