From 3727ace366069c9504548cfd9bd881797a2fa217 Mon Sep 17 00:00:00 2001 From: Dwindi Ramadhana Date: Sun, 14 Jun 2026 18:45:14 +0700 Subject: [PATCH] fix(build): remove unused imports in DiagramEditor and ReactFlowEditor --- package-lock.json | 7 + package.json | 1 + src/pages/DiagramEditor.js | 469 ++++++++++++++++--------------------- 3 files changed, 210 insertions(+), 267 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1bf09c01..05f49444 100755 --- a/package-lock.json +++ b/package-lock.json @@ -43,6 +43,7 @@ "dompurify": "^3.3.0", "file-saver": "^2.0.5", "highlight.js": "^11.11.1", + "html-to-image": "^1.11.13", "html2pdf.js": "^0.12.1", "js-beautify": "^1.15.4", "jspdf": "^3.0.3", @@ -22984,6 +22985,12 @@ "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", "license": "MIT" }, + "node_modules/html-to-image": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/html-to-image/-/html-to-image-1.11.13.tgz", + "integrity": "sha512-cuOPoI7WApyhBElTTb9oqsawRvZ0rHhaHwghRLlTuffoD1B2aDemlCruLeZrUIIdvG7gs9xeELEPm6PhuASqrg==", + "license": "MIT" + }, "node_modules/html-webpack-plugin": { "version": "5.6.7", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.7.tgz", diff --git a/package.json b/package.json index eda71d92..06228b27 100755 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "dompurify": "^3.3.0", "file-saver": "^2.0.5", "highlight.js": "^11.11.1", + "html-to-image": "^1.11.13", "html2pdf.js": "^0.12.1", "js-beautify": "^1.15.4", "jspdf": "^3.0.3", diff --git a/src/pages/DiagramEditor.js b/src/pages/DiagramEditor.js index 35e95e36..0533de90 100755 --- a/src/pages/DiagramEditor.js +++ b/src/pages/DiagramEditor.js @@ -1,126 +1,121 @@ import React, { useState, useRef, useEffect } from "react"; -import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch"; -import mermaid from "mermaid"; import { GitGraph, Plus, Upload, Download, Globe, - Edit3, Type, Columns, Maximize2, Minimize2, - Check, - Copy, FileImage, FileCode2, - ZoomIn, - ZoomOut, - Maximize, - FileDown, Eye, AlertTriangle, + FileText, } from "lucide-react"; import ToolLayout from "../components/ToolLayout"; import CodeMirrorEditor from "../components/CodeMirrorEditor"; -import AdvancedURLFetch from "../components/AdvancedURLFetch"; import SEO from "../components/SEO"; import RelatedTools from "../components/RelatedTools"; - -// Debounce helper -const useDebounce = (value, delay) => { - const [debouncedValue, setDebouncedValue] = useState(value); - useEffect(() => { - const handler = setTimeout(() => { - setDebouncedValue(value); - }, delay); - return () => clearTimeout(handler); - }, [value, delay]); - return debouncedValue; -}; +import ReactFlowEditor from "../components/diagram/ReactFlowEditor"; +import FullscreenAdBanner from "../components/FullscreenAdBanner"; +import { toPng } from "html-to-image"; const DIAGRAM_TEMPLATES = { - flowchart: `flowchart TD - A[Start] --> B{Is it?}; - B -- Yes --> C[OK]; - C --> D[Rethink]; - D --> B; - B -- No ----> E[End];`, - sequence: `sequenceDiagram - participant Alice - participant Bob - Alice->>John: Hello John, how are you? - loop Healthcheck - John->>John: Fight against hypochondria - end - Note right of John: Rational thoughts
prevail! - John-->>Alice: Great! - John->>Bob: How about you? - Bob-->>John: Jolly good!`, - class: `classDiagram - Animal <|-- Duck - Animal <|-- Fish - Animal <|-- Zebra - Animal : +int age - Animal : +String gender - Animal: +isMammal() - Animal: +mate() - class Duck{ - +String beakColor - +swim() - +quack() - } - class Fish{ - -int sizeInFeet - -canEat() - } - class Zebra{ - +bool is_wild - +run() - }`, - state: `stateDiagram-v2 - [*] --> Still - Still --> [*] - - Still --> Moving - Moving --> Still - Moving --> Crash - Crash --> [*]`, - er: `erDiagram - CUSTOMER ||--o{ ORDER : places - ORDER ||--|{ LINE-ITEM : contains - CUSTOMER }|..|{ DELIVERY-ADDRESS : uses`, - gantt: `gantt - title A Gantt Diagram - dateFormat YYYY-MM-DD - section Section - A task :a1, 2014-01-01, 30d - Another task :after a1 , 20d - section Another - Task in sec :2014-01-12 , 12d - another task : 24d`, - pie: `pie title Pets adopted by volunteers - "Dogs" : 386 - "Cats" : 85 - "Rats" : 15`, - git: `gitGraph - commit - commit - branch develop - checkout develop - commit - commit - checkout main - merge develop - commit - commit`, + flowchart: { + nodes: [ + { + id: "1", + type: "process", + position: { x: 250, y: 50 }, + data: { label: "Start" }, + }, + { + id: "2", + type: "decision", + position: { x: 250, y: 150 }, + data: { label: "Is it OK?" }, + }, + { + id: "3", + type: "process", + position: { x: 100, y: 250 }, + data: { label: "Fix it" }, + }, + { + id: "4", + type: "database", + position: { x: 400, y: 250 }, + data: { label: "Save to DB" }, + }, + { + id: "5", + type: "process", + position: { x: 250, y: 350 }, + data: { label: "End" }, + }, + ], + edges: [ + { id: "e1-2", source: "1", target: "2" }, + { + id: "e2-3", + source: "2", + target: "3", + sourceHandle: "left", + label: "No", + }, + { + id: "e2-4", + source: "2", + target: "4", + sourceHandle: "right", + label: "Yes", + }, + { id: "e3-2", source: "3", target: "2", targetHandle: "left" }, + { + id: "e4-5", + source: "4", + target: "5", + sourceHandle: "bottom", + targetHandle: "right", + }, + ], + }, + database: { + nodes: [ + { + id: "users", + type: "database", + position: { x: 100, y: 100 }, + data: { label: "Users Table" }, + }, + { + id: "orders", + type: "database", + position: { x: 400, y: 100 }, + data: { label: "Orders Table" }, + }, + { + id: "process", + type: "process", + position: { x: 250, y: 250 }, + data: { label: "Order Processor" }, + }, + ], + edges: [ + { id: "eu-p", source: "users", target: "process", label: "Read" }, + { id: "ep-o", source: "process", target: "orders", label: "Write" }, + ], + }, }; const DiagramEditor = () => { - const [code, setCode] = useState(DIAGRAM_TEMPLATES.flowchart); - const debouncedCode = useDebounce(code, 500); // 500ms debounce + const [graphData, setGraphData] = useState(DIAGRAM_TEMPLATES.flowchart); + const [code, setCode] = useState( + JSON.stringify(DIAGRAM_TEMPLATES.flowchart, null, 2), + ); const [activeTab, setActiveTab] = useState("create"); const [viewMode, setViewMode] = useState(() => @@ -132,66 +127,34 @@ const DiagramEditor = () => { const [fetching, setFetching] = useState(false); const [selectedTemplate, setSelectedTemplate] = useState("flowchart"); - const [svgContent, setSvgContent] = useState(""); - const svgContainerRef = useRef(null); + const reactFlowWrapper = useRef(null); const fileInputRef = useRef(null); - // Initialize Mermaid + // Sync JSON text input to Graph data useEffect(() => { - mermaid.initialize({ - startOnLoad: false, - theme: "default", // We can sync this with dark mode later - securityLevel: "loose", - fontFamily: - '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', - }); - }, []); - - // Render diagram when debounced code changes - useEffect(() => { - const renderDiagram = async () => { - try { - setError(null); // Clear previous errors - if (!debouncedCode.trim()) { - setSvgContent(""); - return; - } - - // Validate syntax first - const isValid = await mermaid.parse(debouncedCode, { - suppressErrors: true, - }); - - if (isValid) { - const id = `mermaid-${Date.now()}`; - const { svg } = await mermaid.render(id, debouncedCode); - setSvgContent(svg); - } else { - // If parse returns false but doesn't throw, it's still invalid - setError("Syntax error in diagram code"); - } - } catch (err) { - console.error("Mermaid parsing error:", err); - // Extract the most readable part of the error - let errorMessage = "Syntax error"; - if (err.message) { - errorMessage = err.message.split("\n")[0] || "Syntax error"; - } else if (typeof err === "string") { - errorMessage = err.split("\n")[0]; - } - setError(errorMessage); + try { + const parsed = JSON.parse(code); + if (parsed.nodes && parsed.edges) { + setGraphData(parsed); + setError(null); } - }; + } catch (err) { + setError(err.message); + } + }, [code]); - renderDiagram(); - }, [debouncedCode]); + const handleGraphChange = (newGraphData) => { + setGraphData(newGraphData); + setCode(JSON.stringify(newGraphData, null, 2)); + }; // Input Handlers const handleTemplateChange = (e) => { const template = e.target.value; setSelectedTemplate(template); if (DIAGRAM_TEMPLATES[template]) { - setCode(DIAGRAM_TEMPLATES[template]); + setGraphData(DIAGRAM_TEMPLATES[template]); + setCode(JSON.stringify(DIAGRAM_TEMPLATES[template], null, 2)); } }; @@ -234,7 +197,7 @@ const DiagramEditor = () => { } }; - // Export Handlers + // Export Handlers (Updated for ReactFlow) const downloadFile = (content, filename, mimeType) => { const blob = new Blob([content], { type: mimeType }); const url = URL.createObjectURL(blob); @@ -247,41 +210,33 @@ const DiagramEditor = () => { URL.revokeObjectURL(url); }; - const exportSVG = () => { - if (!svgContent) return; - downloadFile(svgContent, "diagram.svg", "image/svg+xml"); + const exportJSON = () => { + downloadFile(code, "diagram.json", "application/json"); }; const exportPNG = () => { - if (!svgContent) return; - const canvas = document.createElement("canvas"); - const ctx = canvas.getContext("2d"); - const img = new Image(); + const flowElement = document.querySelector(".react-flow"); + if (!flowElement) return; - // Create blob URL from SVG - const svg = new Blob([svgContent], { type: "image/svg+xml;charset=utf-8" }); - const DOMURL = window.URL || window.webkitURL || window; - const url = DOMURL.createObjectURL(svg); - - img.onload = () => { - canvas.width = img.width * 2; // High DPI - canvas.height = img.height * 2; - ctx.fillStyle = "white"; // Background - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.drawImage(img, 0, 0, canvas.width, canvas.height); - - const pngUrl = canvas.toDataURL("image/png"); - const a = document.createElement("a"); - a.download = "diagram.png"; - a.href = pngUrl; - a.click(); - DOMURL.revokeObjectURL(url); - }; - img.src = url; - }; - - const exportCode = () => { - downloadFile(code, "diagram.mmd", "text/plain"); + toPng(flowElement, { + backgroundColor: "#ffffff", + width: flowElement.offsetWidth, + height: flowElement.offsetHeight, + style: { + width: "100%", + height: "100%", + transform: "translate(0, 0)", + }, + }) + .then((dataUrl) => { + const a = document.createElement("a"); + a.setAttribute("download", "diagram.png"); + a.setAttribute("href", dataUrl); + a.click(); + }) + .catch((error) => { + setError("Failed to export PNG: " + error.message); + }); }; return ( @@ -298,38 +253,59 @@ const DiagramEditor = () => { description="Create diagrams as code using Mermaid.js with live preview and multi-format export." icon={GitGraph} > - {/* Input Tabs */} + {/* Input Section - Always visible */}
+
+

+ Get Started +

+
+ + {/* Tab Navigation */}
+
@@ -346,17 +322,14 @@ const DiagramEditor = () => { className="tool-input w-full max-w-xs" > - - - - - - - +