Commit 38b620c6 authored by tom's avatar tom

basic implementation

parent b0368b9a
......@@ -8,6 +8,7 @@ function generateCspPolicy() {
descriptors.googleAnalytics(),
descriptors.googleFonts(),
descriptors.googleReCaptcha(),
descriptors.monaco(),
descriptors.sentry(),
descriptors.walletConnect(),
);
......
......@@ -3,5 +3,6 @@ export { app } from './app';
export { googleAnalytics } from './googleAnalytics';
export { googleFonts } from './googleFonts';
export { googleReCaptcha } from './googleReCaptcha';
export { monaco } from './monaco';
export { sentry } from './sentry';
export { walletConnect } from './walletConnect';
import type CspDev from 'csp-dev';
import { KEY_WORDS } from '../utils';
export function monaco(): CspDev.DirectiveDescriptor {
return {
'script-src': [
KEY_WORDS.BLOB,
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/loader.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/editor/editor.main.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/editor/editor.main.nls.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/basic-languages/solidity/solidity.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/base/worker/workerMain.js',
],
'style-src': [
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/editor/editor.main.css',
],
'font-src': [
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/base/browser/ui/codicons/codicon/codicon.ttf',
],
};
}
import { Box, chakra, Flex, Text, Tooltip } from '@chakra-ui/react';
import { Flex, Text, Tooltip } from '@chakra-ui/react';
import { route } from 'nextjs-routes';
import React from 'react';
import type { SmartContract } from 'types/api/contract';
import CodeEditor from 'ui/shared/CodeEditor';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
import CodeEditorMonaco from 'ui/shared/CodeEditorMonaco';
import LinkInternal from 'ui/shared/LinkInternal';
interface Props {
......@@ -37,18 +36,7 @@ const ContractSourceCode = ({ data, hasSol2Yml, address, isViper, filePath, addi
</Tooltip>
) : null;
if (!additionalSource?.length) {
return (
<section>
<Flex justifyContent="space-between" alignItems="center" mb={ 3 }>
{ heading }
{ diagramLink }
<CopyToClipboard text={ data }/>
</Flex>
<CodeEditor value={ data } id="source_code"/>
</section>
);
}
const code = [ { file_path: filePath || 'index.sol', source_code: data }, ...(additionalSource || []) ];
return (
<section>
......@@ -56,19 +44,7 @@ const ContractSourceCode = ({ data, hasSol2Yml, address, isViper, filePath, addi
{ heading }
{ diagramLink }
</Flex>
<Flex flexDir="column" rowGap={ 3 }>
{ [ { file_path: filePath, source_code: data }, ...additionalSource ].map((item, index, array) => (
<Box key={ index }>
<Flex justifyContent="space-between" alignItems="flex-end" mb={ 3 }>
<chakra.span fontSize="sm" wordBreak="break-all" lineHeight="20px">
File { index + 1 } of { array.length }: { item.file_path }
</chakra.span>
<CopyToClipboard text={ item.source_code } ml={ 4 }/>
</Flex>
<CodeEditor value={ item.source_code } id={ `source_code_${ index }` }/>
</Box>
)) }
</Flex>
<CodeEditorMonaco data={ code }/>
</section>
);
};
......
import { chakra, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
import type ReactAce from 'react-ace/lib/ace';
interface Props {
id: string;
value: string;
className?: string;
}
const CodeEditorBase = chakra(({ id, value, className }: Props) => {
const [ AceEditor, setAceEditor ] = React.useState<{default: typeof ReactAce} | null>(null);
React.useEffect(() => {
const load = async() => {
const component = await import('react-ace');
await import('ace-builds/src-noconflict/mode-csharp');
await import('ace-builds/src-noconflict/theme-tomorrow');
await import('ace-builds/src-noconflict/theme-tomorrow_night');
await import('ace-builds/src-noconflict/ext-language_tools');
setAceEditor(component);
};
load();
return () => {
setAceEditor(null);
};
}, []);
const theme = useColorModeValue('tomorrow', 'tomorrow_night');
if (!AceEditor) {
return null;
}
return (
<AceEditor.default
className={ className }
mode="csharp" // TODO need to find mode for solidity
theme={ theme }
value={ value }
name={ id }
editorProps={{ $blockScrolling: true }}
readOnly
width="100%"
showPrintMargin={ false }
maxLines={ 25 }
/>
);
});
const CodeEditor = ({ id, value }: Props) => {
// see theme/components/Textarea.ts variantFilledInactive
const bgColor = useColorModeValue('#f5f5f6', '#1a1b1b');
const gutterBgColor = useColorModeValue('gray.100', '#25282c');
return (
<CodeEditorBase
id={ id }
value={ value }
bgColor={ bgColor }
borderRadius="md"
overflow="hidden"
sx={{
'.ace_gutter': {
backgroundColor: gutterBgColor,
},
}}
/>
);
};
export default React.memo(CodeEditor);
import { Box, useColorMode } from '@chakra-ui/react';
import Editor from '@monaco-editor/react';
import type * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import React from 'react';
export type Monaco = typeof monaco;
interface Props {
data: Array<{ file_path: string; source_code: string }>;
}
const CodeEditorMonaco = ({ data }: Props) => {
const instance = React.useRef<Monaco>();
const { colorMode } = useColorMode();
React.useEffect(() => {
instance.current?.editor.setTheme(colorMode === 'light' ? 'blockscout-light' : 'blockscout-dark');
}, [ colorMode ]);
const handleEditorDidMount = React.useCallback((editor: monaco.editor.IStandaloneCodeEditor, monaco: Monaco) => {
instance.current = monaco;
monaco.editor.defineTheme('blockscout-light', {
base: 'vs',
inherit: true,
rules: [],
colors: {
'editor.background': '#f5f5f6',
},
});
monaco.editor.defineTheme('blockscout-dark', {
base: 'vs-dark',
inherit: true,
rules: [],
colors: {
'editor.background': '#1a1b1b',
},
});
monaco.editor.setTheme(colorMode === 'light' ? 'blockscout-light' : 'blockscout-dark');
// componentDidMount
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ ]);
return (
<Box overflow="hidden" borderRadius="md">
<Editor
height="500px"
language="sol"
defaultValue={ data[0].source_code }
options={{ readOnly: true, inlayHints: { enabled: 'off' }, minimap: { enabled: false } }}
onMount={ handleEditorDidMount }
/>
</Box>
);
};
export default CodeEditorMonaco;
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment