diff --git a/.env b/.env new file mode 100644 index 0000000..b8475cc --- /dev/null +++ b/.env @@ -0,0 +1 @@ +VITE_MONACO_URL=/monaco-editor \ No newline at end of file diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..af18361 --- /dev/null +++ b/.env.production @@ -0,0 +1 @@ +VITE_MONACO_URL=//unpkg.com/monaco-editor@0.47.0 \ No newline at end of file diff --git a/index.html b/index.html index b7c3083..b9fcb63 100644 --- a/index.html +++ b/index.html @@ -1,14 +1,16 @@ - - - - - GOST API Manage - - - - - -
- - - + + + + + GOST API Manage + + + + + + + +
+ + + diff --git a/package.json b/package.json index 946a412..c521d7d 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "qs": "^6.11.2", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-monaco-editor": "^0.54.0", "uuid": "^9.0.1" }, "devDependencies": { diff --git a/src/Pages/Manage.tsx b/src/Pages/Manage.tsx index 26071a4..5aef0e5 100644 --- a/src/Pages/Manage.tsx +++ b/src/Pages/Manage.tsx @@ -21,8 +21,7 @@ import { useServerConfig, } from "../uitls/server"; import { download, jsonFormat } from "../uitls"; -import { MonacoEditor } from "../uitls/userMonacoWorker"; -import Ctx from "../uitls/ctx"; +import { CodeEditor } from "../uitls/useMonacoEdit"; import * as API from "../api"; import ListCard, { ProCard } from "../components/ListCard"; import ChainCard from "../components/ListCard/Chains"; @@ -291,17 +290,17 @@ const Manage = () => { {/*
{jsonFormat(gostConfig!)}
*/} - + >
diff --git a/src/components/Forms/Json.tsx b/src/components/Forms/Json.tsx index 91d1410..60f5d61 100644 --- a/src/components/Forms/Json.tsx +++ b/src/components/Forms/Json.tsx @@ -3,12 +3,11 @@ import ReactDOM from "react-dom/client"; import { Button, Dropdown, Form, FormInstance, Space } from "antd"; import { DownOutlined } from "@ant-design/icons"; import { jsonFormat, jsonStringFormat, jsonParse, jsonEdit } from "../../uitls"; -import * as monaco from "monaco-editor"; -import { MonacoEditor, getModel, model, modelUri } from "../../uitls/userMonacoWorker"; import { Template } from "../../templates"; // import { render } from "react-dom"; // import { useServerConfig } from "../../uitls/server"; import ModalForm, { ModalFormProps } from "../ModalForm"; +import { CodeEditor } from "../../uitls/useMonacoEdit"; const template2menu: any = (template: Template) => { const { children, ...other } = template; @@ -180,21 +179,20 @@ const JsonForm: React.FC = (props) => { }, ]} > - + }} /> + {/* */} diff --git a/src/monaco.d.ts b/src/monaco.d.ts new file mode 100644 index 0000000..85fb4cc --- /dev/null +++ b/src/monaco.d.ts @@ -0,0 +1,4 @@ +namespace globalThis { + const monacoIsReady: Promise; + const monaco: any; +} diff --git a/src/uitls/useMonacoEdit.tsx b/src/uitls/useMonacoEdit.tsx new file mode 100644 index 0000000..2696251 --- /dev/null +++ b/src/uitls/useMonacoEdit.tsx @@ -0,0 +1,194 @@ +import React, { useEffect, useRef, useState } from "react"; +import { useBindValue } from "./use"; +import type * as Monaco from "monaco-editor"; +import classnames from "classnames"; + +(function () { + const require = (window as any).require; + let monacoURL; + const MONACO_URL = import.meta.env.VITE_MONACO_URL || '/monaco-editor'; + if(/^(http[s]:)?\/\//.test(MONACO_URL)){ + monacoURL = MONACO_URL + '/min/vs' + }else{ + const baseURL = new URL(import.meta.env.BASE_URL, location.href).href; + monacoURL = new URL(`${MONACO_URL}/min/vs`, baseURL).href; + } + + // if(import.meta.env.PROD && import.meta.env.VITE_MONACO_URL){ + // monacoURL = import.meta.env.VITE_MONACO_URL + '/min/vs'; + // }else{ + // const baseURL = new URL(import.meta.env.BASE_URL, location.href).href; + // monacoURL = new URL("./monaco-editor/min/vs", baseURL).href; + // } + + // console.log(`import_meta_env_BASE_URL`, import.meta.env.BASE_URL); + // console.log("baseURL", baseURL); + // const monacoURL = `//unpkg.com/monaco-editor@0.47.0/min/vs` + require.config({ paths: { vs: `${monacoURL}` } }); + require.config({ + "vs/nls": { + availableLanguages: { + "*": "zh-cn", + }, + }, + }); + (window as any).monacoIsReady = new Promise((resolve, reject) => { + require(["vs/editor/editor.main"], function () { + resolve(monaco); + }); + }); +})(); + +monacoIsReady.then(() => { + // monacoPython.register(); //注册 关键字,内置函数 代码提示 ; + monaco.languages.json.jsonDefaults.setDiagnosticsOptions({ + allowComments: true, + trailingCommas: "warning", + validate: true, + }); + // monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true); +}); + +type CodeEditorProps = { + className?: string; + style?: React.CSSProperties; + language?: string; + value?: string; + theme?: string; + height?: string | number; + defaultValue?: string; + onChange?: (value: string) => void; + options?: Monaco.editor.IStandaloneEditorConstructionOptions; +}; + +const defOptions: Monaco.editor.IStandaloneEditorConstructionOptions = { + minimap: { enabled: false }, + automaticLayout: true, +}; + +const CodeEditor_: React.ForwardRefRenderFunction< + Monaco.editor.IStandaloneCodeEditor, + CodeEditorProps +> = (props, ref) => { + const { onChange, options, height, className, theme = "vs", style } = props; + const [language, setLanguage] = useBindValue(props.language, "javascript"); + const [value, setValue] = useBindValue(props.value, props.defaultValue, ""); + const [isReady, setReady] = useState(false); + const divEl = useRef(null); + const editor = useRef(null); + const self = useRef({}); + + React.useImperativeHandle(ref, () => { + return editor.current!; + }); + + React.useImperativeHandle( + self, + () => { + return { + onChange, + }; + }, + [onChange] + ); + + useEffect(() => { + // let editor: any; + if (divEl.current) { + const el = divEl.current; + let _editor: Monaco.editor.IStandaloneCodeEditor; + monacoIsReady.then(() => { + _editor = editor.current = monaco.editor.create(el, { + value: value, + language: language, + theme, + ...defOptions, + ...options, + }); + console.log("editor.current", editor.current.getDomNode()); + _editor.onDidChangeModelContent(function (event: any) { + const _value = _editor.getValue(); + setValue(_value); + self.current?.onChange?.(_value); + }); + + _editor.addCommand(monaco.KeyMod.Alt | monaco.KeyCode.KeyX, (e) => { + _editor.getAction("my-autoWrap-toggle")?.run(); + }); + + _editor.addAction({ + id: "my-autoWrap-toggle", + label: "切换自动换行", + keybindings: [ + monaco.KeyMod.Alt | monaco.KeyCode.KeyZ, + // monaco.KeyMod.chord( + // monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyK, + // monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyM + // ), + ], + + // A precondition for this action. + // precondition: null, + + // A rule to evaluate on top of the precondition in order to dispatch the keybindings. + // keybindingContext: null, + + // contextMenuGroupId: "navigation", + // contextMenuOrder: 1.5, + + // Method that will be executed when the action is triggered. + // @param editor The editor instance is passed in as a convenience + run: function (ed, arg) { + // alert("i'm running => " + ed.getPosition()); + // console.log("my-autoWrap-toggle", arg); + const workWrap = ed.getOption(monaco.editor.EditorOption.wordWrap); + ed.updateOptions({ + wordWrap: workWrap === "on" ? "off" : "on", + }); + }, + }); + + setReady(true); + }); + // let xc: any; + // const resizeObserver = new ResizeObserver((entries) => { + // // _editor?.layout(); + // // console.log("resizeObserver"); + // if (xc) clearTimeout(xc); + // xc = setTimeout(() => { + // _editor?.layout(); + // }, 100); + // }); + // resizeObserver.observe(el); + return () => { + _editor?.dispose?.(); + // resizeObserver.unobserve(el); + // resizeObserver.disconnect(); + }; + } + }, []); + + useEffect(() => { + if (editor.current) { + if (value != editor.current.getValue()) { + editor.current.setValue(value); + } + } + }, [value]); + + return ( +
+ ); +}; + +export const CodeEditor = React.forwardRef(CodeEditor_); diff --git a/src/uitls/userMonacoWorker.ts b/src/uitls/userMonacoWorker.ts.bak similarity index 58% rename from src/uitls/userMonacoWorker.ts rename to src/uitls/userMonacoWorker.ts.bak index 7bb49b3..430b551 100644 --- a/src/uitls/userMonacoWorker.ts +++ b/src/uitls/userMonacoWorker.ts.bak @@ -1,8 +1,9 @@ /* eslint-disable */ +import MonacoEditor from "react-monaco-editor"; +// import { monaco } from "react-monaco-editor"; import * as monaco from "monaco-editor"; import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker"; import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker"; -import MonacoEditor from "react-monaco-editor"; // import cssWorker from "monaco-editor/esm/vs/language/css/css.worker?worker"; // import htmlWorker from "monaco-editor/esm/vs/language/html/html.worker?worker"; // import tsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker"; @@ -31,46 +32,47 @@ self.MonacoEnvironment = { }, }; -var modelUri = monaco.Uri.parse("a://b/foo.json"); // a made up unique URI for our model -var getModel = (value: string) => { - return monaco.editor.createModel(value, "json", modelUri); -}; -var model = getModel(''); +// var modelUri = monaco.Uri.parse("a://b/foo.json"); // a made up unique URI for our model +// var getModel = (value: string) => { +// return monaco.editor.createModel(value, "json", modelUri); +// }; +// var model = getModel(""); monaco.languages.json.jsonDefaults.setDiagnosticsOptions({ allowComments: true, trailingCommas: "warning", validate: true, // json 数据格式测试 - schemas: [ - { - uri: "http://gost/config.json", // id of the first schema - fileMatch: [modelUri.toString()], // associate with our model - schema: { - type: "object", - properties: { - p1: { - enum: ["v1", "v2"], - }, - p2: { - $ref: "http://myserver/bar-schema.json", // reference the second schema - }, - }, - }, - }, - { - uri: "http://myserver/bar-schema.json", // id of the second schema - schema: { - type: "object", - properties: { - q1: { - enum: ["x1", "x2"], - }, - }, - }, - }, - ], + // schemas: [ + // { + // uri: "http://gost/config.json", // id of the first schema + // fileMatch: [modelUri.toString()], // associate with our model + // schema: { + // type: "object", + // properties: { + // p1: { + // enum: ["v1", "v2"], + // }, + // p2: { + // $ref: "http://myserver/bar-schema.json", // reference the second schema + // }, + // }, + // }, + // }, + // { + // uri: "http://myserver/bar-schema.json", // id of the second schema + // schema: { + // type: "object", + // properties: { + // q1: { + // enum: ["x1", "x2"], + // }, + // }, + // }, + // }, + // ], }); + monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true); -export { MonacoEditor, modelUri, getModel, model }; +export { MonacoEditor }; diff --git a/vite.config.ts b/vite.config.ts index c5af135..744786c 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -21,7 +21,7 @@ export default defineConfig(({ command, mode }) => { output: { // manualChunks 配置 manualChunks: { - monaco: ["monaco-editor"], + // monaco: ["monaco-editor"], antd: ["antd"], }, },