iprov
This commit is contained in:
@@ -36,7 +36,7 @@ const DEFAULT_VIEWPORT_HEIGHT = 800
|
||||
|
||||
type Props = AbstractNodeProps<RenderingNodeData>
|
||||
|
||||
function RenderingNodeComponent({ id, data, width, height }: Props) {
|
||||
function RenderingNodeComponent({ id, data, width, height, selected }: Props) {
|
||||
const [renderedContent, setRenderedContent] = useState<string | null>(null)
|
||||
const [error, setError] = useState<null | { kind: string; message: string }>(null)
|
||||
const [loading, setLoading] = useState(false)
|
||||
@@ -529,6 +529,31 @@ function RenderingNodeComponent({ id, data, width, height }: Props) {
|
||||
img.src = dataUrl
|
||||
}, [id, renderedContent, isSvgOutput])
|
||||
|
||||
const copyPng = useCallback(() => {
|
||||
if (!renderedContent || !isSvgOutput) return
|
||||
const dataUrl = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(renderedContent)
|
||||
const img = new Image()
|
||||
img.onload = () => {
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = img.naturalWidth
|
||||
canvas.height = img.naturalHeight
|
||||
const ctx = canvas.getContext('2d')
|
||||
if (!ctx) return
|
||||
ctx.drawImage(img, 0, 0)
|
||||
canvas.toBlob((blob) => {
|
||||
if (blob) navigator.clipboard?.write([new ClipboardItem({ 'image/png': blob })]).catch(() => {})
|
||||
}, 'image/png')
|
||||
}
|
||||
img.onerror = () => {}
|
||||
img.src = dataUrl
|
||||
}, [renderedContent, isSvgOutput])
|
||||
|
||||
const copySvg = useCallback(() => {
|
||||
if (!renderedContent || !isSvgOutput) return
|
||||
const blob = new Blob([renderedContent], { type: 'image/svg+xml' })
|
||||
navigator.clipboard?.write([new ClipboardItem({ 'image/svg+xml': blob })]).catch(() => {})
|
||||
}, [renderedContent, isSvgOutput])
|
||||
|
||||
const status = loading ? 'loading' : error ? 'error' : renderedContent ? 'success' : 'initial'
|
||||
|
||||
const [viewportDraft, setViewportDraft] = useState({ width: viewportWidth, height: viewportHeight })
|
||||
@@ -545,7 +570,7 @@ function RenderingNodeComponent({ id, data, width, height }: Props) {
|
||||
|
||||
return (
|
||||
<NodeStatusIndicator status={status} variant="border" width={dimensions?.width} height={dimensions?.height}>
|
||||
<BaseNode className="min-w-96 min-h-[320px]" dimensions={dimensions} resizable nodeId={id} handles={<InputHandle id="ain" nodeId={id} />}>
|
||||
<BaseNode className="min-w-96 min-h-[320px]" dimensions={dimensions} resizable nodeId={id} selected={selected} handles={<InputHandle id="ain" nodeId={id} />}>
|
||||
<BaseNodeHeaderRow icon={<Sparkles className="size-4" />} title={<NodeHeaderTitle nodeId={id} displayTitle={id} />} />
|
||||
|
||||
<BaseNodeContent>
|
||||
@@ -602,14 +627,20 @@ function RenderingNodeComponent({ id, data, width, height }: Props) {
|
||||
<MenubarSub>
|
||||
<MenubarSeparator />
|
||||
<MenubarSubTrigger className="text-xs" disabled={!isSvgOutput}>
|
||||
Export
|
||||
Export / Copy
|
||||
</MenubarSubTrigger>
|
||||
<MenubarSubContent className="min-w-[10rem]">
|
||||
<MenubarItem className="text-xs" onClick={downloadPng} disabled={!isSvgOutput}>
|
||||
PNG
|
||||
</MenubarItem>
|
||||
<MenubarSubContent className="min-w-[10rem]" aria-label="Export or copy diagram">
|
||||
<MenubarItem className="text-xs" onClick={downloadSvg} disabled={!isSvgOutput}>
|
||||
SVG
|
||||
Download SVG
|
||||
</MenubarItem>
|
||||
<MenubarItem className="text-xs" onClick={downloadPng} disabled={!isSvgOutput}>
|
||||
Download PNG
|
||||
</MenubarItem>
|
||||
<MenubarItem className="text-xs" onClick={copySvg} disabled={!isSvgOutput}>
|
||||
Copy SVG
|
||||
</MenubarItem>
|
||||
<MenubarItem className="text-xs" onClick={copyPng} disabled={!isSvgOutput}>
|
||||
Copy image
|
||||
</MenubarItem>
|
||||
</MenubarSubContent>
|
||||
</MenubarSub>
|
||||
|
||||
Reference in New Issue
Block a user