mirror of
https://github.com/drawdb-io/drawdb.git
synced 2025-10-21 10:43:58 +00:00
Switch to monaco-editor from codemirror (#403)
* switch to monaco-editor * fix styles
This commit is contained in:
47
src/components/CodeEditor/index.jsx
Normal file
47
src/components/CodeEditor/index.jsx
Normal file
@@ -0,0 +1,47 @@
|
||||
import { Editor } from "@monaco-editor/react";
|
||||
import { useDiagram, useSettings } from "../../hooks";
|
||||
import { Button, Toast } from "@douyinfe/semi-ui";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { IconCopy } from "@douyinfe/semi-icons";
|
||||
import { setUpDBML } from "./setUpDBML";
|
||||
import "./styles.css";
|
||||
|
||||
export default function CodeEditor({ showCopyButton, ...props }) {
|
||||
const { settings } = useSettings();
|
||||
const { database } = useDiagram();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const copyCode = () => {
|
||||
navigator.clipboard
|
||||
.writeText(props.value)
|
||||
.then(() => Toast.success(t("copied_to_clipboard")))
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
});
|
||||
};
|
||||
|
||||
const handleEditorMount = (editor, monaco) => {
|
||||
setUpDBML(monaco, database);
|
||||
|
||||
setTimeout(() => {
|
||||
editor.getAction("editor.action.formatDocument").run();
|
||||
}, 300);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<Editor
|
||||
{...props}
|
||||
theme={settings.mode === "light" ? "vs" : "vs-dark"}
|
||||
onMount={handleEditorMount}
|
||||
/>
|
||||
{showCopyButton && (
|
||||
<Button
|
||||
className="absolute right-6 bottom-2 z-10"
|
||||
icon={<IconCopy />}
|
||||
onClick={copyCode}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
152
src/components/CodeEditor/setUpDBML.js
Normal file
152
src/components/CodeEditor/setUpDBML.js
Normal file
@@ -0,0 +1,152 @@
|
||||
import { dbToTypes } from "../../data/datatypes";
|
||||
|
||||
export function setUpDBML(monaco, database) {
|
||||
monaco.languages.register({ id: "dbml" });
|
||||
|
||||
console.log(Object.keys(dbToTypes[database]));
|
||||
|
||||
monaco.languages.setMonarchTokensProvider("dbml", {
|
||||
defaultToken: "",
|
||||
tokenPostfix: ".dbml",
|
||||
ignoreCase: true,
|
||||
|
||||
keywords: [
|
||||
"table",
|
||||
"tablegroup",
|
||||
"project",
|
||||
"enum",
|
||||
"ref",
|
||||
"as",
|
||||
"indexes",
|
||||
"index",
|
||||
"note",
|
||||
"delete",
|
||||
"update",
|
||||
"pk",
|
||||
"increment",
|
||||
"not",
|
||||
"null",
|
||||
"unique",
|
||||
"default",
|
||||
],
|
||||
|
||||
typeKeywords: Object.keys(dbToTypes[database]),
|
||||
|
||||
operators: [
|
||||
"=",
|
||||
">",
|
||||
"<",
|
||||
"!",
|
||||
"~",
|
||||
"?",
|
||||
":",
|
||||
"==",
|
||||
"<=",
|
||||
">=",
|
||||
"!=",
|
||||
"&&",
|
||||
"||",
|
||||
"++",
|
||||
"--",
|
||||
"+",
|
||||
"-",
|
||||
"*",
|
||||
"/",
|
||||
"&",
|
||||
"|",
|
||||
"^",
|
||||
],
|
||||
|
||||
symbols: /[=><!~?:&|+\-*/^%]+/,
|
||||
escapes:
|
||||
/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,
|
||||
|
||||
tokenizer: {
|
||||
root: [
|
||||
[
|
||||
/[a-zA-Z_$][\w$]*/,
|
||||
{
|
||||
cases: {
|
||||
"@keywords": "keyword",
|
||||
"@typeKeywords": "type",
|
||||
"@default": "identifier",
|
||||
},
|
||||
},
|
||||
],
|
||||
{ include: "@whitespace" },
|
||||
[/[{}()[\]]/, "@brackets"],
|
||||
[/[<>](?!@symbols)/, "@brackets"],
|
||||
[
|
||||
/@symbols/,
|
||||
{
|
||||
cases: {
|
||||
"@operators": "operator",
|
||||
"@default": "",
|
||||
},
|
||||
},
|
||||
],
|
||||
[/\d*\.\d+([eE][-+]?\d+)?/, "number.float"],
|
||||
[/0[xX][0-9a-fA-F]+/, "number.hex"],
|
||||
[/\d+/, "number"],
|
||||
[/[;,.]/, "delimiter"],
|
||||
[/"([^"\\]|\\.)*$/, "string.invalid"],
|
||||
[/'([^'\\]|\\.)*$/, "string.invalid"],
|
||||
[/"/, { token: "string.quote", bracket: "@open", next: "@dqstring" }],
|
||||
[/'/, { token: "string.quote", bracket: "@open", next: "@sqstring" }],
|
||||
],
|
||||
|
||||
dqstring: [
|
||||
[/[^\\"]+/, "string"],
|
||||
[/@escapes/, "string.escape"],
|
||||
[/\\./, "string.escape.invalid"],
|
||||
[/"/, { token: "string.quote", bracket: "@close", next: "@pop" }],
|
||||
],
|
||||
|
||||
sqstring: [
|
||||
[/[^\\']+/, "string"],
|
||||
[/@escapes/, "string.escape"],
|
||||
[/\\./, "string.escape.invalid"],
|
||||
[/'/, { token: "string.quote", bracket: "@close", next: "@pop" }],
|
||||
],
|
||||
|
||||
comment: [
|
||||
[/[^\\/*]+/, "comment"],
|
||||
[/\/\*/, "comment", "@push"],
|
||||
["\\*/", "comment", "@pop"],
|
||||
[/[\\/*]/, "comment"],
|
||||
],
|
||||
|
||||
whitespace: [
|
||||
[/[ \t\r\n]+/, "white"],
|
||||
[/\/\*/, "comment", "@comment"],
|
||||
[/\/\/.*$/, "comment"],
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
monaco.languages.setLanguageConfiguration("dbml", {
|
||||
comments: {
|
||||
lineComment: "//",
|
||||
blockComment: ["/*", "*/"],
|
||||
},
|
||||
brackets: [
|
||||
["{", "}"],
|
||||
["[", "]"],
|
||||
["(", ")"],
|
||||
],
|
||||
autoClosingPairs: [
|
||||
{ open: "{", close: "}" },
|
||||
{ open: "[", close: "]" },
|
||||
{ open: "(", close: ")" },
|
||||
{ open: '"', close: '"' },
|
||||
{ open: "'", close: "'" },
|
||||
],
|
||||
surroundingPairs: [
|
||||
{ open: "{", close: "}" },
|
||||
{ open: "[", close: "]" },
|
||||
{ open: "(", close: ")" },
|
||||
{ open: '"', close: '"' },
|
||||
{ open: "'", close: "'" },
|
||||
],
|
||||
});
|
||||
}
|
4
src/components/CodeEditor/styles.css
Normal file
4
src/components/CodeEditor/styles.css
Normal file
@@ -0,0 +1,4 @@
|
||||
.monaco-editor,
|
||||
.monaco-editor > .overflow-guard {
|
||||
border-radius: 6px;
|
||||
}
|
@@ -1,52 +0,0 @@
|
||||
import { useState } from "react";
|
||||
import { sql } from "@codemirror/lang-sql";
|
||||
import { json } from "@codemirror/lang-json";
|
||||
import { vscodeDark } from "@uiw/codemirror-theme-vscode";
|
||||
import { githubLight } from "@uiw/codemirror-theme-github";
|
||||
import { useSettings } from "../../../hooks";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import CodeMirror from "@uiw/react-codemirror";
|
||||
|
||||
const languageExtension = {
|
||||
sql: [sql()],
|
||||
json: [json()],
|
||||
};
|
||||
|
||||
export default function Code({ value, language }) {
|
||||
const { t } = useTranslation();
|
||||
const { settings } = useSettings();
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const copyCode = () => {
|
||||
navigator.clipboard
|
||||
.writeText(value)
|
||||
.then(() => {
|
||||
setCopied(true);
|
||||
setTimeout(() => {
|
||||
setCopied(false);
|
||||
}, 2000);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<CodeMirror
|
||||
value={value}
|
||||
height="360px"
|
||||
extensions={languageExtension[language]}
|
||||
editable={false}
|
||||
theme={settings.mode === "dark" ? vscodeDark : githubLight}
|
||||
/>
|
||||
<button
|
||||
onClick={copyCode}
|
||||
className={`absolute right-4 top-2 px-2 py-1 rounded-sm ${settings.mode === "dark" ? "bg-zinc-700" : "bg-zinc-200"}`}
|
||||
>
|
||||
<i className={`bi bi-clipboard${copied ? "-check" : ""} me-2`} />
|
||||
{t("copy")}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -34,12 +34,19 @@ import ImportSource from "./ImportSource";
|
||||
import SetTableWidth from "./SetTableWidth";
|
||||
import Language from "./Language";
|
||||
import Share from "./Share";
|
||||
import Code from "./Code";
|
||||
import CodeEditor from "../../CodeEditor";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { importSQL } from "../../../utils/importSQL";
|
||||
import { databases } from "../../../data/databases";
|
||||
import { isRtl } from "../../../i18n/utils/rtl";
|
||||
|
||||
const extensionToLanguage = {
|
||||
md: "markdown",
|
||||
sql: "sql",
|
||||
dbml: "dbml",
|
||||
json: "json",
|
||||
};
|
||||
|
||||
export default function Modal({
|
||||
modal,
|
||||
setModal,
|
||||
@@ -52,7 +59,8 @@ export default function Modal({
|
||||
importFrom,
|
||||
}) {
|
||||
const { t, i18n } = useTranslation();
|
||||
const { tables, setTables, setRelationships, database, setDatabase } = useDiagram();
|
||||
const { tables, setTables, setRelationships, database, setDatabase } =
|
||||
useDiagram();
|
||||
const { setNotes } = useNotes();
|
||||
const { setAreas } = useAreas();
|
||||
const { setTypes } = useTypes();
|
||||
@@ -307,7 +315,13 @@ export default function Modal({
|
||||
{modal === MODAL.IMG ? (
|
||||
<Image src={exportData.data} alt="Diagram" height={280} />
|
||||
) : (
|
||||
<Code value={exportData.data} language={exportData.extension} />
|
||||
<CodeEditor
|
||||
height={360}
|
||||
value={exportData.data}
|
||||
language={extensionToLanguage[exportData.extension]}
|
||||
options={{ readOnly: true }}
|
||||
showCopyButton={true}
|
||||
/>
|
||||
)}
|
||||
<div className="text-sm font-semibold mt-2">{t("filename")}:</div>
|
||||
<Input
|
||||
|
@@ -34,6 +34,7 @@ export const getModalWidth = (modal) => {
|
||||
switch (modal) {
|
||||
case MODAL.LANGUAGE:
|
||||
case MODAL.OPEN:
|
||||
case MODAL.CODE:
|
||||
case MODAL.NEW:
|
||||
return 740;
|
||||
default:
|
||||
|
Reference in New Issue
Block a user