first version
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import AceEditor from 'react-ace';
|
||||
import 'brace/theme/tomorrow';
|
||||
import 'brace/ext/language_tools';
|
||||
|
||||
import Style from './CodeEditor.less';
|
||||
import Dialog from '../../components/Dialog';
|
||||
import { Select, Option } from '../../components/Select';
|
||||
import Button from '../../components/Button';
|
||||
|
||||
const languages = [
|
||||
'javascript',
|
||||
'typescript',
|
||||
'text',
|
||||
'java',
|
||||
'c_cpp',
|
||||
'python',
|
||||
'ruby',
|
||||
'php',
|
||||
'golang',
|
||||
'csharp',
|
||||
'html',
|
||||
'css',
|
||||
'sql',
|
||||
'json',
|
||||
];
|
||||
|
||||
interface LoadedLanguage {
|
||||
[key: string]: boolean;
|
||||
}
|
||||
const loadedLanguage: LoadedLanguage = {};
|
||||
|
||||
interface CodeEditorProps {
|
||||
visible: boolean;
|
||||
onClose: () => void;
|
||||
onSend: (language: string, code: string) => void;
|
||||
}
|
||||
|
||||
function CodeEditor(props: CodeEditorProps) {
|
||||
const { visible, onClose, onSend } = props;
|
||||
|
||||
const [language, setLanguage] = useState('javascript');
|
||||
const [value, setValue] = useState('');
|
||||
const [timestamp, setTimestamp] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
setValue('');
|
||||
}
|
||||
}, [visible]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
// 动态加载语言包
|
||||
if (visible && !loadedLanguage[language]) {
|
||||
/**
|
||||
* 为了减小打包产物体积, 这里是逐个引入所需的语音包
|
||||
* 如果直接用变量路径, 会将该目录下的文件全部打包
|
||||
* 另外不单个引入也不好设置 webpackChunkName
|
||||
*/
|
||||
switch (language) {
|
||||
case 'javascript': {
|
||||
// @ts-ignore
|
||||
await import(
|
||||
/* webpackChunkName: "react-ace-mode-javascript" */ 'brace/mode/javascript'
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'typescript': {
|
||||
// @ts-ignore
|
||||
await import(
|
||||
/* webpackChunkName: "react-ace-mode-typescript" */ 'brace/mode/typescript'
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'java': {
|
||||
// @ts-ignore
|
||||
await import(
|
||||
/* webpackChunkName: "react-ace-mode-java" */ 'brace/mode/java'
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'c_cpp': {
|
||||
// @ts-ignore
|
||||
await import(
|
||||
/* webpackChunkName: "react-ace-mode-c_cpp" */ 'brace/mode/c_cpp'
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'python': {
|
||||
// @ts-ignore
|
||||
await import(
|
||||
/* webpackChunkName: "react-ace-mode-python" */ 'brace/mode/python'
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'ruby': {
|
||||
// @ts-ignore
|
||||
await import(
|
||||
/* webpackChunkName: "react-ace-mode-ruby" */ 'brace/mode/ruby'
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'php': {
|
||||
// @ts-ignore
|
||||
await import(
|
||||
/* webpackChunkName: "react-ace-mode-php" */ 'brace/mode/php'
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'golang': {
|
||||
// @ts-ignore
|
||||
await import(
|
||||
/* webpackChunkName: "react-ace-mode-golang" */ 'brace/mode/golang'
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'csharp': {
|
||||
// @ts-ignore
|
||||
await import(
|
||||
/* webpackChunkName: "react-ace-mode-csharp" */ 'brace/mode/csharp'
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'html': {
|
||||
// @ts-ignore
|
||||
await import(
|
||||
/* webpackChunkName: "react-ace-mode-html" */ 'brace/mode/html'
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'css': {
|
||||
// @ts-ignore
|
||||
await import(
|
||||
/* webpackChunkName: "react-ace-mode-css" */ 'brace/mode/css'
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'text': {
|
||||
// @ts-ignore
|
||||
await import(
|
||||
/* webpackChunkName: "react-ace-mode-text" */ 'brace/mode/markdown'
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'sql': {
|
||||
// @ts-ignore
|
||||
await import(
|
||||
/* webpackChunkName: "react-ace-mode-sql" */ 'brace/mode/sql'
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'json': {
|
||||
// @ts-ignore
|
||||
await import(
|
||||
/* webpackChunkName: "react-ace-mode-json" */ 'brace/mode/json'
|
||||
);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
console.warn('不支持的语言包', language);
|
||||
}
|
||||
}
|
||||
loadedLanguage[language] = true;
|
||||
setTimestamp(Date.now());
|
||||
}
|
||||
})();
|
||||
}, [visible, language]);
|
||||
|
||||
function renderEditor() {
|
||||
if (!loadedLanguage[language]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const editorProps = {
|
||||
theme: 'tomorrow',
|
||||
value,
|
||||
onChange: (newValue: string) => setValue(newValue),
|
||||
fontSize: 12,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
showPrintMargin: true,
|
||||
showGutter: true,
|
||||
highlightActiveLine: true,
|
||||
setOptions: {
|
||||
enableBasicAutocompletion: true,
|
||||
enableLiveAutocompletion: true,
|
||||
enableSnippets: false,
|
||||
showLineNumbers: true,
|
||||
tabSize: 4,
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<AceEditor
|
||||
mode={language === 'text' ? 'markdown' : language}
|
||||
{...editorProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog
|
||||
className={Style.codeEditor}
|
||||
title="请输入要发送的代码"
|
||||
visible={visible}
|
||||
onClose={onClose}
|
||||
>
|
||||
<div className={Style.container}>
|
||||
<div className={Style.selectContainer}>
|
||||
<h3 className={Style.title}>编程语言: </h3>
|
||||
<Select
|
||||
className={Style.languageSelect}
|
||||
defaultValue={languages[0]}
|
||||
// @ts-ignore
|
||||
onSelect={(lang: string) => setLanguage(lang)}
|
||||
>
|
||||
{languages.map((lang) => (
|
||||
<Option value={lang} key={lang}>
|
||||
{lang}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</div>
|
||||
<div className={Style.editorContainer}>
|
||||
{renderEditor()}
|
||||
</div>
|
||||
<Button
|
||||
className={Style.sendButton}
|
||||
onClick={() => onSend(language, value)}
|
||||
>
|
||||
发送
|
||||
</Button>
|
||||
</div>
|
||||
</Dialog>
|
||||
<span className="hide">{timestamp}</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default CodeEditor;
|
||||
Reference in New Issue
Block a user