feat: add multi file capabillity
This commit is contained in:
@ -15,10 +15,13 @@ import {
|
|||||||
import { userSelector, isDonationModalOpenSelector } from '../../../redux';
|
import { userSelector, isDonationModalOpenSelector } from '../../../redux';
|
||||||
import { Loader } from '../../../components/helpers';
|
import { Loader } from '../../../components/helpers';
|
||||||
|
|
||||||
|
import './editor.css';
|
||||||
|
|
||||||
const MonacoEditor = React.lazy(() => import('react-monaco-editor'));
|
const MonacoEditor = React.lazy(() => import('react-monaco-editor'));
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
canFocus: PropTypes.bool,
|
canFocus: PropTypes.bool,
|
||||||
|
challengeFiles: PropTypes.object,
|
||||||
containerRef: PropTypes.any.isRequired,
|
containerRef: PropTypes.any.isRequired,
|
||||||
contents: PropTypes.string,
|
contents: PropTypes.string,
|
||||||
dimensions: PropTypes.object,
|
dimensions: PropTypes.object,
|
||||||
@ -26,6 +29,8 @@ const propTypes = {
|
|||||||
ext: PropTypes.string,
|
ext: PropTypes.string,
|
||||||
fileKey: PropTypes.string,
|
fileKey: PropTypes.string,
|
||||||
inAccessibilityMode: PropTypes.bool.isRequired,
|
inAccessibilityMode: PropTypes.bool.isRequired,
|
||||||
|
initialEditorContent: PropTypes.string,
|
||||||
|
initialExt: PropTypes.string,
|
||||||
saveEditorContent: PropTypes.func.isRequired,
|
saveEditorContent: PropTypes.func.isRequired,
|
||||||
setAccessibilityMode: PropTypes.func.isRequired,
|
setAccessibilityMode: PropTypes.func.isRequired,
|
||||||
setEditorFocusability: PropTypes.func,
|
setEditorFocusability: PropTypes.func,
|
||||||
@ -93,6 +98,12 @@ class Editor extends Component {
|
|||||||
constructor(...props) {
|
constructor(...props) {
|
||||||
super(...props);
|
super(...props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
code: '',
|
||||||
|
ext: '',
|
||||||
|
fileKey: ''
|
||||||
|
};
|
||||||
|
|
||||||
this.options = {
|
this.options = {
|
||||||
fontSize: '18px',
|
fontSize: '18px',
|
||||||
scrollBeyondLastLine: false,
|
scrollBeyondLastLine: false,
|
||||||
@ -133,6 +144,11 @@ class Editor extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
editorDidMount = (editor, monaco) => {
|
editorDidMount = (editor, monaco) => {
|
||||||
|
this.setState({
|
||||||
|
code: this.props.challengeFiles.indexcss.contents,
|
||||||
|
ext: this.props.challengeFiles.indexcss.ext,
|
||||||
|
fileKey: this.props.challengeFiles.indexcss.key
|
||||||
|
});
|
||||||
this._editor = editor;
|
this._editor = editor;
|
||||||
editor.updateOptions({
|
editor.updateOptions({
|
||||||
accessibilitySupport: this.props.inAccessibilityMode ? 'on' : 'auto'
|
accessibilitySupport: this.props.inAccessibilityMode ? 'on' : 'auto'
|
||||||
@ -206,8 +222,12 @@ class Editor extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onChange = editorValue => {
|
onChange = editorValue => {
|
||||||
const { updateFile, fileKey } = this.props;
|
const { updateFile } = this.props;
|
||||||
|
const { fileKey } = this.state;
|
||||||
updateFile({ key: fileKey, editorValue });
|
updateFile({ key: fileKey, editorValue });
|
||||||
|
this.setState({
|
||||||
|
code: editorValue
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
@ -217,11 +237,18 @@ class Editor extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { contents, ext, theme, fileKey } = this.props;
|
const { code, ext, fileKey } = this.state;
|
||||||
|
const { theme } = this.props;
|
||||||
const editorTheme = theme === 'night' ? 'vs-dark-custom' : 'vs-custom';
|
const editorTheme = theme === 'night' ? 'vs-dark-custom' : 'vs-custom';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Suspense fallback={<Loader timeout={600} />}>
|
<Suspense fallback={<Loader timeout={600} />}>
|
||||||
<span className='notranslate'>
|
<span className='notranslate'>
|
||||||
|
<div className='monaco-editor-tabs'>
|
||||||
|
<div className='monaco-editor-tab'>index.html</div>
|
||||||
|
<div className='monaco-editor-tab'>script.js</div>
|
||||||
|
<div className='monaco-editor-tab'>styles.css</div>
|
||||||
|
</div>
|
||||||
<MonacoEditor
|
<MonacoEditor
|
||||||
editorDidMount={this.editorDidMount}
|
editorDidMount={this.editorDidMount}
|
||||||
editorWillMount={this.editorWillMount}
|
editorWillMount={this.editorWillMount}
|
||||||
@ -230,7 +257,7 @@ class Editor extends Component {
|
|||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
options={this.options}
|
options={this.options}
|
||||||
theme={editorTheme}
|
theme={editorTheme}
|
||||||
value={contents}
|
value={code}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
@ -222,14 +222,12 @@ class ShowClassic extends Component {
|
|||||||
renderEditor() {
|
renderEditor() {
|
||||||
const { files } = this.props;
|
const { files } = this.props;
|
||||||
|
|
||||||
const challengeFile = first(Object.keys(files).map(key => files[key]));
|
|
||||||
return (
|
return (
|
||||||
challengeFile && (
|
files && (
|
||||||
<Editor
|
<Editor
|
||||||
|
challengeFiles={files}
|
||||||
containerRef={this.containerRef}
|
containerRef={this.containerRef}
|
||||||
ref={this.editorRef}
|
ref={this.editorRef}
|
||||||
{...challengeFile}
|
|
||||||
fileKey={challengeFile.key}
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -346,6 +344,14 @@ export const query = graphql`
|
|||||||
src
|
src
|
||||||
}
|
}
|
||||||
files {
|
files {
|
||||||
|
indexcss {
|
||||||
|
key
|
||||||
|
ext
|
||||||
|
name
|
||||||
|
contents
|
||||||
|
head
|
||||||
|
tail
|
||||||
|
}
|
||||||
indexhtml {
|
indexhtml {
|
||||||
key
|
key
|
||||||
ext
|
ext
|
||||||
|
24
client/src/templates/Challenges/classic/editor.css
Normal file
24
client/src/templates/Challenges/classic/editor.css
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
.monaco-editor-tabs {
|
||||||
|
display: flex;
|
||||||
|
padding: 0px 10px;
|
||||||
|
background-color: var(--primary-background);
|
||||||
|
border-bottom: 2px solid var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.monaco-editor-tab {
|
||||||
|
position: relative;
|
||||||
|
top: 2px;
|
||||||
|
padding: 4px 16px;
|
||||||
|
border: 2px solid var(--primary-color);
|
||||||
|
border-left: none;
|
||||||
|
background-color: var(--secondary-background);
|
||||||
|
}
|
||||||
|
|
||||||
|
.monaco-editor-tab:first-child {
|
||||||
|
border-left: 2px solid var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.monaco-editor-tab-selected {
|
||||||
|
background-color: var(--primary-background);
|
||||||
|
border-bottom: 2px solid var(--primary-background);
|
||||||
|
}
|
@ -16,13 +16,16 @@ import {
|
|||||||
|
|
||||||
const htmlCatch = '\n<!--fcc-->\n';
|
const htmlCatch = '\n<!--fcc-->\n';
|
||||||
const jsCatch = '\n;/*fcc*/\n';
|
const jsCatch = '\n;/*fcc*/\n';
|
||||||
|
const cssCatch = '\n/*fcc*/\n';
|
||||||
|
|
||||||
const defaultTemplate = ({ source }) => `
|
const defaultTemplate = ({ source }) => {
|
||||||
|
return `
|
||||||
<body id='display-body'style='margin:8px;'>
|
<body id='display-body'style='margin:8px;'>
|
||||||
<!-- fcc-start-source -->
|
<!-- fcc-start-source -->
|
||||||
${source}
|
${source}
|
||||||
<!-- fcc-end-source -->
|
<!-- fcc-end-source -->
|
||||||
</body>`;
|
</body>`;
|
||||||
|
};
|
||||||
|
|
||||||
const wrapInScript = partial(
|
const wrapInScript = partial(
|
||||||
transformContents,
|
transformContents,
|
||||||
@ -30,11 +33,12 @@ const wrapInScript = partial(
|
|||||||
);
|
);
|
||||||
const wrapInStyle = partial(
|
const wrapInStyle = partial(
|
||||||
transformContents,
|
transformContents,
|
||||||
content => `${htmlCatch}<style>${content}</style>`
|
content => `${htmlCatch}<style>${content}${cssCatch}</style>`
|
||||||
);
|
);
|
||||||
const setExtToHTML = partial(setExt, 'html');
|
const setExtToHTML = partial(setExt, 'html');
|
||||||
const padContentWithJsCatch = partial(compileHeadTail, jsCatch);
|
const padContentWithJsCatch = partial(compileHeadTail, jsCatch);
|
||||||
const padContentWithHTMLCatch = partial(compileHeadTail, htmlCatch);
|
const padContentWithCssCatch = partial(compileHeadTail, cssCatch);
|
||||||
|
// const padContentWithHTMLCatch = partial(compileHeadTail, htmlCatch);
|
||||||
|
|
||||||
export const jsToHtml = cond([
|
export const jsToHtml = cond([
|
||||||
[
|
[
|
||||||
@ -52,7 +56,7 @@ export const cssToHtml = cond([
|
|||||||
[
|
[
|
||||||
matchesProperty('ext', 'css'),
|
matchesProperty('ext', 'css'),
|
||||||
flow(
|
flow(
|
||||||
padContentWithHTMLCatch,
|
padContentWithCssCatch,
|
||||||
wrapInStyle,
|
wrapInStyle,
|
||||||
setExtToHTML
|
setExtToHTML
|
||||||
)
|
)
|
||||||
|
@ -20,6 +20,8 @@ function defaultFile(lang) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
function createCodeGetter(key, regEx, seeds) {
|
function createCodeGetter(key, regEx, seeds) {
|
||||||
|
console.log('seeds');
|
||||||
|
console.log(seeds);
|
||||||
return container => {
|
return container => {
|
||||||
const {
|
const {
|
||||||
properties: { id }
|
properties: { id }
|
||||||
|
Reference in New Issue
Block a user