import { React, useContext, useState } from "react"; import { IconCaretdown, IconChevronRight, IconShareStroked, IconChevronUp, IconChevronDown, IconCheckboxTick, IconSaveStroked, IconUndo, IconRedo, } from "@douyinfe/semi-icons"; import { Link } from "react-router-dom"; import icon from "../assets/icon_dark_64.png"; import { Avatar, AvatarGroup, Button, Divider, Dropdown, Form, Image, Modal, Spin, Input, Upload, Banner, } from "@douyinfe/semi-ui"; import { toPng, toJpeg, toSvg } from "html-to-image"; import { saveAs } from "file-saver"; import { diagramObjectIsValid, enterFullscreen, exitFullscreen, } from "../utils"; import { AreaContext, LayoutContext, NoteContext, SettingsContext, TableContext, } from "../pages/editor"; import { AddTable, AddArea, AddNote } from "./custom_icons"; import { defaultTableTheme, defaultNoteTheme } from "../data/data"; import CodeMirror from "@uiw/react-codemirror"; import { json } from "@codemirror/lang-json"; import jsPDF from "jspdf"; export default function ControlPanel(props) { const MODAL = { NONE: 0, IMG: 1, CODE: 2, IMPORT: 3, }; const [visible, setVisible] = useState(MODAL.NONE); const [exportData, setExportData] = useState({ data: "", filename: `diagram_${new Date().toISOString()}`, extension: "", }); const [error, setError] = useState(null); const { layout, setLayout } = useContext(LayoutContext); const { setSettings } = useContext(SettingsContext); const { relationships, tables, setTables } = useContext(TableContext); const { notes, setNotes } = useContext(NoteContext); const { areas, setAreas } = useContext(AreaContext); const menu = { File: { New: { children: [], function: () => console.log("New"), }, "New window": { children: [], function: () => {}, }, Save: { children: [], function: () => {}, }, "Save as": { children: [], function: () => {}, }, Share: { children: [], function: () => {}, }, Rename: { children: [], function: () => {}, }, Import: { children: [], function: () => { setVisible(MODAL.IMPORT); }, }, "Export as": { children: [ { PNG: () => { toPng(document.getElementById("canvas")).then(function (dataUrl) { setExportData((prev) => ({ ...prev, data: dataUrl, extension: "png", })); }); setVisible(MODAL.IMG); }, }, { JPEG: () => { toJpeg(document.getElementById("canvas"), { quality: 0.95 }).then( function (dataUrl) { setExportData((prev) => ({ ...prev, data: dataUrl, extension: "jpeg", })); } ); setVisible(MODAL.IMG); }, }, { JSON: () => { setVisible(MODAL.CODE); const result = JSON.stringify( { tables: tables, relationships: relationships, notes: notes, subjectAreas: areas, }, null, 2 ); setExportData((prev) => ({ ...prev, data: result, extension: "json", })); }, }, { SVG: () => { const filter = (node) => node.tagName !== "i"; toSvg(document.getElementById("canvas"), { filter: filter }).then( function (dataUrl) { setExportData((prev) => ({ ...prev, data: dataUrl, extension: "svg", })); } ); setVisible(MODAL.IMG); }, }, { PDF: () => { const canvas = document.getElementById("canvas"); toJpeg(canvas).then(function (dataUrl) { const doc = new jsPDF("l", "px", [ canvas.offsetWidth, canvas.offsetHeight, ]); doc.addImage( dataUrl, "jpeg", 0, 0, canvas.offsetWidth, canvas.offsetHeight ); doc.save(`${exportData.filename}.pdf`); }); }, }, ], function: () => {}, }, "Export source": { children: [ { MySQL: () => {} }, { PostgreSQL: () => {} }, { DBML: () => {} }, ], function: () => {}, }, Properties: { children: [], function: () => {}, }, Close: { children: [], function: () => {}, }, }, Edit: { Undo: { children: [], function: () => {}, }, Redo: { children: [], function: () => {}, }, Cut: { children: [], function: () => {}, }, Copy: { children: [], function: () => {}, }, "Copy as image": { children: [], function: () => {}, }, Paste: { children: [], function: () => {}, }, Delete: { children: [], function: () => {}, }, "Edit table": { children: [], function: () => {}, }, }, View: { Toolbar: { children: [], function: () => {}, }, Grid: { children: [], function: () => {}, }, Sidebar: { children: [], function: () => {}, }, Editor: { children: [], function: () => {}, }, "Strict mode": { children: [], function: () => { setSettings((prev) => ({ ...prev, strictMode: !prev.strictMode })); }, }, "Field summary": { children: [], function: () => { setSettings((prev) => ({ ...prev, showFieldSummary: !prev.showFieldSummary, })); }, }, "Reset view": { children: [], function: () => {}, }, "View schema": { children: [], function: () => {}, }, Theme: { children: [{ Light: () => {} }, { Dark: () => {} }], function: () => {}, }, "Zoom in": { children: [], function: () => {}, }, "Zoom out": { children: [], function: () => {}, }, Fullscreen: { children: [], function: enterFullscreen, }, }, Logs: { "Open logs": { children: [], function: () => {}, }, "Commit changes": { children: [], function: () => {}, }, "Revert changes": { children: [], function: () => {}, }, "View commits": { children: [], function: () => {}, }, }, Help: { Shortcuts: { children: [], function: () => {}, }, "Ask us on discord": { children: [], function: () => {}, }, "Tweet us": { children: [], function: () => {}, }, "Found a bug": { children: [], function: () => {}, }, }, }; return (
{layout.header && header()}
{layoutDropdown()} Fit window {[ "25%", "50%", "75%", "100%", "125%", "150%", "200%", "300%", ].map((e, i) => ( {e} ))}
%
} /> } trigger="click" >
zoom
{ if (visible === MODAL.IMG) { saveAs( exportData.data, `${exportData.filename}.${exportData.extension}` ); } else if (visible === MODAL.CODE) { const blob = new Blob([exportData.data], { type: "text/plain;charset=utf-8", }); saveAs(blob, `${exportData.filename}.${exportData.extension}`); } else if (visible === MODAL.IMPORT) { } }} afterClose={() => { setExportData((prev) => ({ data: "", extension: "", filename: `diagram_${new Date().toISOString()}`, })); setError(null); }} onCancel={() => setVisible(MODAL.NONE)} centered closeOnEsc={true} okText={`${visible === MODAL.IMPORT ? "Import" : "Export"}`} cancelText="Cancel" width={520} > {visible === MODAL.IMPORT ? (
{ const f = fileList[0].fileInstance; if (!f) { return; } const reader = new FileReader(); reader.onload = function (event) { if (f.type === "application/json") { let jsonObject = null; try { jsonObject = JSON.parse(event.target.result); } catch (error) { setError("Invalid JSON. The file contains an error."); return; } if (!diagramObjectIsValid(jsonObject)) { setError( "The file is missing necessary properties for a diagram." ); return; } } }; reader.readAsText(f); return { autoRemove: false, fileInstance: file.fileInstance, status: "success", shouldUpload: false, }; }} draggable={true} dragMainText="Click to upload the file or drag and drop the file here" dragSubText="Support json" accept="application/json,.txt" onRemove={() => setError(null)} onFileChange={() => setError(null)} limit={1} > {error && ( {error}
} /> )} ) : exportData.data !== "" || exportData.data ? ( <> {visible === MODAL.IMG ? ( Diagram ) : (
)}
Filename:
{`.${exportData.extension}`}} onChange={(value) => setExportData((prev) => ({ ...prev, filename: value })) } field="filename" /> ) : (
)}
); function header() { return ( ); } function layoutDropdown() { return ( ) : (
) } onClick={() => setLayout((prev) => ({ ...prev, header: !prev.header, })) } > Header
) : (
) } onClick={() => setLayout((prev) => ({ ...prev, tables: !prev.tables, })) } > Tables
) : (
) } onClick={() => setLayout((prev) => ({ ...prev, relationships: !prev.relationships, })) } > Relationships
) : (
) } onClick={() => setLayout((prev) => ({ ...prev, issues: !prev.issues, })) } > Issues
) : (
) } onClick={() => setLayout((prev) => ({ ...prev, areas: !prev.areas, })) } > Subject areas
) : (
) } onClick={() => setLayout((prev) => ({ ...prev, editor: !prev.editor, })) } > Editor
) : (
) } onClick={() => setLayout((prev) => ({ ...prev, notes: !prev.notes, })) } > Notes
} > ) : (
) } onClick={() => setLayout((prev) => ({ ...prev, sidebar: !prev.sidebar, })) } > Sidebar
) : (
) } onClick={() => setLayout((prev) => ({ ...prev, services: !prev.services, })) } > Services
) : (
) } onClick={() => { if (layout.fullscreen) { exitFullscreen(); } else { enterFullscreen(); } setLayout((prev) => ({ ...prev, fullscreen: !prev.fullscreen, })); }} > Fullscreen
} trigger="click" >
); } }