mirror of https://github.com/embarklabs/embark.git
Merge pull request #1032 from embark-framework/features/resizable-editor-main
Make the editor resizable
This commit is contained in:
commit
1d31e20476
|
@ -10121,6 +10121,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"re-resizable": {
|
||||||
|
"version": "4.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-4.9.3.tgz",
|
||||||
|
"integrity": "sha512-JKzmZdUAYWs85YErkmZNB7hjGR9qUOHFUZUtEplZlEZBFHRguiWck5J+HFTy/NjlMJtqQsYPQq57nQAO2BuRRg=="
|
||||||
|
},
|
||||||
"react": {
|
"react": {
|
||||||
"version": "16.4.2",
|
"version": "16.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-16.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-16.4.2.tgz",
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"qs": "^6.5.2",
|
"qs": "^6.5.2",
|
||||||
"raf": "3.4.0",
|
"raf": "3.4.0",
|
||||||
|
"re-resizable": "^4.9.3",
|
||||||
"react": "^16.4.2",
|
"react": "^16.4.2",
|
||||||
"react-blockies": "^1.4.0",
|
"react-blockies": "^1.4.0",
|
||||||
"react-bootstrap-typeahead": "^3.2.4",
|
"react-bootstrap-typeahead": "^3.2.4",
|
||||||
|
|
|
@ -21,7 +21,8 @@ const style = (theme) => ({
|
||||||
top: 0,
|
top: 0,
|
||||||
bottom: '40px',
|
bottom: '40px',
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0
|
right: 0,
|
||||||
|
minWidth: '175px'
|
||||||
},
|
},
|
||||||
node: {
|
node: {
|
||||||
base: {
|
base: {
|
||||||
|
@ -214,7 +215,7 @@ class FileExplorer extends React.Component {
|
||||||
style={style(this.props.theme)}
|
style={style(this.props.theme)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Label className="hidden-toogle mb-0 pt-2 pr-2 pb-1 border-top text-right">
|
<Label className="hidden-toggle mb-0 pt-2 pr-2 pb-1 border-top text-right">
|
||||||
<span className="mr-2 align-top" style={{"fontSize": "12px"}}>Show hidden files</span>
|
<span className="mr-2 align-top" style={{"fontSize": "12px"}}>Show hidden files</span>
|
||||||
<AppSwitch color="success" variant="pill" size="sm" onChange={this.props.toggleShowHiddenFiles}/>
|
<AppSwitch color="success" variant="pill" size="sm" onChange={this.props.toggleShowHiddenFiles}/>
|
||||||
</Label>
|
</Label>
|
||||||
|
|
|
@ -46,6 +46,10 @@ class TextEditor extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
window.removeEventListener("resize", this.handleResize);
|
||||||
|
}
|
||||||
|
|
||||||
handleResize = () => editor.layout();
|
handleResize = () => editor.layout();
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,6 +138,10 @@ class TextEditor extends React.Component {
|
||||||
this.handleResize();
|
this.handleResize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addEditorTabs(e, file) {
|
||||||
|
e.preventDefault(); this.props.addEditorTabs(file);
|
||||||
|
}
|
||||||
|
|
||||||
renderTabs() {
|
renderTabs() {
|
||||||
return (
|
return (
|
||||||
<ul className="list-inline m-0 p-0">
|
<ul className="list-inline m-0 p-0">
|
||||||
|
@ -144,7 +152,7 @@ class TextEditor extends React.Component {
|
||||||
})}>
|
})}>
|
||||||
<a
|
<a
|
||||||
href="#switch-tab"
|
href="#switch-tab"
|
||||||
onClick={() => this.props.addEditorTabs(file)}
|
onClick={(e) => this.addEditorTabs(e, file)}
|
||||||
className="p-2 text-muted"
|
className="p-2 text-muted"
|
||||||
>
|
>
|
||||||
{file.name}
|
{file.name}
|
||||||
|
|
|
@ -8,3 +8,7 @@ export const DEPLOYMENT_PIPELINES = {
|
||||||
embark: 'embark'
|
embark: 'embark'
|
||||||
};
|
};
|
||||||
export const DEFAULT_HOST = process.env.NODE_ENV === 'development' ? 'localhost:8000' : window.location.host;
|
export const DEFAULT_HOST = process.env.NODE_ENV === 'development' ? 'localhost:8000' : window.location.host;
|
||||||
|
export const OPERATIONS = {
|
||||||
|
MORE: 1,
|
||||||
|
LESS: -1
|
||||||
|
};
|
||||||
|
|
|
@ -4,11 +4,12 @@
|
||||||
margin-top: -1.5rem !important;
|
margin-top: -1.5rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden-toogle {
|
.hidden-toggle {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-editor__debuggerLine {
|
.text-editor__debuggerLine {
|
||||||
|
@ -34,8 +35,12 @@
|
||||||
.editor-aside {
|
.editor-aside {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.aside-opened .text-editor-container {
|
|
||||||
max-height: 500px;
|
.resizer-handle {
|
||||||
}
|
width: 15px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle-horizontal {
|
||||||
|
height: 15px !important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,21 +9,51 @@ import TextEditorToolbarContainer from './TextEditorToolbarContainer';
|
||||||
import {fetchEditorTabs as fetchEditorTabsAction} from '../actions';
|
import {fetchEditorTabs as fetchEditorTabsAction} from '../actions';
|
||||||
import {getCurrentFile} from '../reducers/selectors';
|
import {getCurrentFile} from '../reducers/selectors';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
import Resizable from 're-resizable';
|
||||||
|
import {OPERATIONS} from '../constants';
|
||||||
|
|
||||||
import './EditorContainer.css';
|
import './EditorContainer.css';
|
||||||
|
|
||||||
class EditorContainer extends React.Component {
|
class EditorContainer extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {currentAsideTab: {}, showHiddenFiles: false, currentFile: this.props.currentFile};
|
this.DEFAULT_EDITOR_WIDTH = 85;
|
||||||
|
this.DEFAULT_EDITOR_WIDTH_SMALL = 75;
|
||||||
|
this.DEFAULT_HEIGHT = 500;
|
||||||
|
this.SMALL_SIZE = 768;
|
||||||
|
this.windowWidth = window.innerWidth;
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
currentAsideTab: {}, showHiddenFiles: false, currentFile: this.props.currentFile,
|
||||||
|
editorHeight: this.DEFAULT_HEIGHT,
|
||||||
|
editorWidth: ((this.windowWidth < this.SMALL_SIZE) ? this.DEFAULT_EDITOR_WIDTH_SMALL : this.DEFAULT_EDITOR_WIDTH) + '%',
|
||||||
|
asideHeight: '100%', asideWidth: '25%',
|
||||||
|
isSmallSize: (this.windowWidth < this.SMALL_SIZE)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.fetchEditorTabs();
|
this.props.fetchEditorTabs();
|
||||||
|
window.addEventListener("resize", this.updateDimensions.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
window.removeEventListener("resize", this.updateDimensions.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDimensions() {
|
||||||
|
this.windowWidth = window.innerWidth;
|
||||||
|
|
||||||
|
const isSmallSize = (this.windowWidth < this.SMALL_SIZE);
|
||||||
|
if (this.state.isSmallSize !== isSmallSize) {
|
||||||
|
this.setState({isSmallSize});
|
||||||
|
this.changeEditorWidth(isSmallSize ? OPERATIONS.MORE : OPERATIONS.LESS);
|
||||||
|
this.editor.handleResize();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
if(this.props.currentFile.path !== prevProps.currentFile.path) {
|
if (this.props.currentFile.path !== prevProps.currentFile.path) {
|
||||||
this.setState({currentFile: this.props.currentFile});
|
this.setState({currentFile: this.props.currentFile});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,38 +73,116 @@ class EditorContainer extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
openAsideTab(newTab) {
|
openAsideTab(newTab) {
|
||||||
|
if (!this.state.isSmallSize) {
|
||||||
|
this.changeEditorWidth((!this.state.currentAsideTab.label) ? OPERATIONS.LESS : OPERATIONS.MORE);
|
||||||
|
}
|
||||||
if (newTab.label === this.state.currentAsideTab.label) {
|
if (newTab.label === this.state.currentAsideTab.label) {
|
||||||
|
this.editor.handleResize();
|
||||||
return this.setState({currentAsideTab: {}});
|
return this.setState({currentAsideTab: {}});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({currentAsideTab: newTab});
|
this.setState({currentAsideTab: newTab});
|
||||||
}
|
}
|
||||||
|
|
||||||
textEditorMdSize() {
|
changeEditorWidth(operation) {
|
||||||
return this.state.currentAsideTab.label ? 7 : 10;
|
this.setState({
|
||||||
|
editorWidth: (parseFloat(this.state.editorWidth) + (operation * parseFloat(this.state.asideWidth))) + '%'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTextEditor() {
|
||||||
|
const height = !!(this.state.isSmallSize && this.state.currentAsideTab.label) ? this.state.editorHeight : 'auto';
|
||||||
|
return (
|
||||||
|
<Resizable
|
||||||
|
size={{width: this.state.editorWidth, height: height}}
|
||||||
|
minWidth="20%" maxWidth="90%"
|
||||||
|
handleClasses={{left: 'resizer-handle', right: 'resizer-handle', bottom: 'resize-handle-horizontal'}}
|
||||||
|
onResizeStop={(e, direction, ref, d) => {
|
||||||
|
this.setState({
|
||||||
|
editorWidth: ref.style.width,
|
||||||
|
editorHeight: this.state.editorHeight + d.height
|
||||||
|
});
|
||||||
|
this.editor.handleResize();
|
||||||
|
}}
|
||||||
|
className="text-editor-container border-left"
|
||||||
|
enable={{
|
||||||
|
top: false,
|
||||||
|
right: false,
|
||||||
|
bottom: !!(this.state.isSmallSize && this.state.currentAsideTab.label),
|
||||||
|
left: true,
|
||||||
|
topRight: false,
|
||||||
|
bottomRight: false,
|
||||||
|
bottomLeft: false,
|
||||||
|
topLeft: false
|
||||||
|
}}>
|
||||||
|
<TextEditorContainer
|
||||||
|
ref={instance => {
|
||||||
|
this.editor = instance ? instance.getWrappedInstance().editor : null;
|
||||||
|
}}
|
||||||
|
currentFile={this.props.currentFile}
|
||||||
|
onFileContentChange={(newContent) => this.onFileContentChange(newContent)}/>
|
||||||
|
</Resizable>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAside() {
|
||||||
|
const aside = (
|
||||||
|
<div className="editor-aside">
|
||||||
|
<TextEditorAsideContainer currentAsideTab={this.state.currentAsideTab}
|
||||||
|
currentFile={this.props.currentFile}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.windowWidth < this.SMALL_SIZE) {
|
||||||
|
return (<Col sm={12} className="border-left-0 relative">
|
||||||
|
{aside}
|
||||||
|
</Col>);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Resizable defaultSize={{width: this.state.asideWidth, height: 'auto'}}
|
||||||
|
maxWidth='60%' minWidth='17%'
|
||||||
|
handleClasses={{left: 'resizer-handle', right: 'resizer-handle'}}
|
||||||
|
className="border-left-0 relative"
|
||||||
|
enable={{
|
||||||
|
top: false,
|
||||||
|
right: false,
|
||||||
|
bottom: false,
|
||||||
|
left: true,
|
||||||
|
topRight: false,
|
||||||
|
bottomRight: false,
|
||||||
|
bottomLeft: false,
|
||||||
|
topLeft: false
|
||||||
|
}}
|
||||||
|
onResize={(e, direction, ref, _d) => {
|
||||||
|
this.setState({
|
||||||
|
editorWidth: this.DEFAULT_EDITOR_WIDTH - parseFloat(ref.style.width) + '%'
|
||||||
|
});
|
||||||
|
}}>
|
||||||
|
{aside}
|
||||||
|
</Resizable>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Row noGutters className={classnames('h-100', 'editor--grid', {'aside-opened': this.state.currentAsideTab.label})}>
|
<Row noGutters
|
||||||
|
className={classnames('h-100', 'editor--grid', {'aside-opened': this.state.currentAsideTab.label})}>
|
||||||
<Col xs={12}>
|
<Col xs={12}>
|
||||||
<TextEditorToolbarContainer openAsideTab={(newTab) => this.openAsideTab(newTab)}
|
<TextEditorToolbarContainer openAsideTab={(newTab) => this.openAsideTab(newTab)}
|
||||||
isContract={this.isContract()}
|
isContract={this.isContract()}
|
||||||
currentFile={this.props.currentFile}
|
currentFile={this.props.currentFile}
|
||||||
activeTab={this.state.currentAsideTab}/>
|
activeTab={this.state.currentAsideTab}/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col sm={4} md={2} xl={2} lg={2} className="border-right">
|
|
||||||
<FileExplorerContainer showHiddenFiles={this.state.showHiddenFiles} toggleShowHiddenFiles={() => this.toggleShowHiddenFiles()} />
|
<Col className="border-right">
|
||||||
|
<FileExplorerContainer showHiddenFiles={this.state.showHiddenFiles}
|
||||||
|
toggleShowHiddenFiles={() => this.toggleShowHiddenFiles()}/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col sm={8} md={this.textEditorMdSize()} className="text-editor-container">
|
|
||||||
<TextEditorContainer currentFile={this.props.currentFile} onFileContentChange={(newContent) => this.onFileContentChange(newContent)} />
|
{this.renderTextEditor()}
|
||||||
</Col>
|
|
||||||
{this.state.currentAsideTab.label &&
|
{this.state.currentAsideTab.label && this.renderAside()}
|
||||||
<Col sm={12} md={3} className="border-left-0 relative">
|
|
||||||
<div className="editor-aside">
|
|
||||||
<TextEditorAsideContainer currentAsideTab={this.state.currentAsideTab}
|
|
||||||
currentFile={this.props.currentFile}/>
|
|
||||||
</div>
|
|
||||||
</Col>}
|
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -95,6 +203,6 @@ EditorContainer.propTypes = {
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
{fetchEditorTabs: fetchEditorTabsAction.request},
|
{fetchEditorTabs: fetchEditorTabsAction.request}
|
||||||
)(EditorContainer);
|
)(EditorContainer);
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,10 @@ class TextEditorContainer extends React.Component {
|
||||||
addEditorTabs={this.props.addEditorTabs}
|
addEditorTabs={this.props.addEditorTabs}
|
||||||
debuggerLine={this.props.debuggerLine}
|
debuggerLine={this.props.debuggerLine}
|
||||||
onFileContentChange={this.props.onFileContentChange}
|
onFileContentChange={this.props.onFileContentChange}
|
||||||
theme={this.props.theme} />
|
theme={this.props.theme}
|
||||||
|
ref={instance => {
|
||||||
|
if (instance) this.editor = instance;
|
||||||
|
}}/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +48,7 @@ TextEditorContainer.propTypes = {
|
||||||
onFileContentChange: PropTypes.func,
|
onFileContentChange: PropTypes.func,
|
||||||
toggleBreakpoints: PropTypes.func,
|
toggleBreakpoints: PropTypes.func,
|
||||||
breakpoints: PropTypes.array,
|
breakpoints: PropTypes.array,
|
||||||
toggleBreakpoint: PropTypes.object,
|
toggleBreakpoint: PropTypes.func,
|
||||||
fetchEditorTabs: PropTypes.func,
|
fetchEditorTabs: PropTypes.func,
|
||||||
removeEditorTabs: PropTypes.func,
|
removeEditorTabs: PropTypes.func,
|
||||||
addEditorTabs: PropTypes.func,
|
addEditorTabs: PropTypes.func,
|
||||||
|
@ -57,9 +60,11 @@ TextEditorContainer.propTypes = {
|
||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
{
|
{
|
||||||
toggleBreakpoint,
|
toggleBreakpoint: toggleBreakpoint.request,
|
||||||
fetchEditorTabs: fetchEditorTabsAction.request,
|
fetchEditorTabs: fetchEditorTabsAction.request,
|
||||||
removeEditorTabs: removeEditorTabsAction.request,
|
removeEditorTabs: removeEditorTabsAction.request,
|
||||||
addEditorTabs: addEditorTabsAction.request
|
addEditorTabs: addEditorTabsAction.request
|
||||||
},
|
},
|
||||||
|
null,
|
||||||
|
{ withRef: true }
|
||||||
)(TextEditorContainer);
|
)(TextEditorContainer);
|
||||||
|
|
Loading…
Reference in New Issue