mirror of https://github.com/embarklabs/embark.git
feat(cockpit): make editor resizable
This commit is contained in:
parent
a714e078c4
commit
1030607813
|
@ -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": {
|
||||
"version": "16.4.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.4.2.tgz",
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
"prop-types": "^15.6.2",
|
||||
"qs": "^6.5.2",
|
||||
"raf": "3.4.0",
|
||||
"re-resizable": "^4.9.3",
|
||||
"react": "^16.4.2",
|
||||
"react-blockies": "^1.4.0",
|
||||
"react-bootstrap-typeahead": "^3.2.4",
|
||||
|
|
|
@ -21,7 +21,8 @@ const style = (theme) => ({
|
|||
top: 0,
|
||||
bottom: '40px',
|
||||
left: 0,
|
||||
right: 0
|
||||
right: 0,
|
||||
minWidth: '175px'
|
||||
},
|
||||
node: {
|
||||
base: {
|
||||
|
@ -214,7 +215,7 @@ class FileExplorer extends React.Component {
|
|||
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>
|
||||
<AppSwitch color="success" variant="pill" size="sm" onChange={this.props.toggleShowHiddenFiles}/>
|
||||
</Label>
|
||||
|
|
|
@ -46,6 +46,10 @@ class TextEditor extends React.Component {
|
|||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener("resize", this.handleResize);
|
||||
}
|
||||
|
||||
handleResize = () => editor.layout();
|
||||
|
||||
|
||||
|
@ -134,6 +138,10 @@ class TextEditor extends React.Component {
|
|||
this.handleResize();
|
||||
}
|
||||
|
||||
addEditorTabs(e, file) {
|
||||
e.preventDefault(); this.props.addEditorTabs(file);
|
||||
}
|
||||
|
||||
renderTabs() {
|
||||
return (
|
||||
<ul className="list-inline m-0 p-0">
|
||||
|
@ -144,7 +152,7 @@ class TextEditor extends React.Component {
|
|||
})}>
|
||||
<a
|
||||
href="#switch-tab"
|
||||
onClick={() => this.props.addEditorTabs(file)}
|
||||
onClick={(e) => this.addEditorTabs(e, file)}
|
||||
className="p-2 text-muted"
|
||||
>
|
||||
{file.name}
|
||||
|
|
|
@ -8,3 +8,7 @@ export const DEPLOYMENT_PIPELINES = {
|
|||
embark: 'embark'
|
||||
};
|
||||
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;
|
||||
}
|
||||
|
||||
.hidden-toogle {
|
||||
.hidden-toggle {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.text-editor__debuggerLine {
|
||||
|
@ -34,8 +35,12 @@
|
|||
.editor-aside {
|
||||
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 {getCurrentFile} from '../reducers/selectors';
|
||||
import classnames from 'classnames';
|
||||
import Resizable from 're-resizable';
|
||||
import {OPERATIONS} from '../constants';
|
||||
|
||||
import './EditorContainer.css';
|
||||
|
||||
class EditorContainer extends React.Component {
|
||||
constructor(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() {
|
||||
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) {
|
||||
if(this.props.currentFile.path !== prevProps.currentFile.path) {
|
||||
if (this.props.currentFile.path !== prevProps.currentFile.path) {
|
||||
this.setState({currentFile: this.props.currentFile});
|
||||
}
|
||||
}
|
||||
|
@ -43,38 +73,116 @@ class EditorContainer extends React.Component {
|
|||
}
|
||||
|
||||
openAsideTab(newTab) {
|
||||
if (!this.state.isSmallSize) {
|
||||
this.changeEditorWidth((!this.state.currentAsideTab.label) ? OPERATIONS.LESS : OPERATIONS.MORE);
|
||||
}
|
||||
if (newTab.label === this.state.currentAsideTab.label) {
|
||||
this.editor.handleResize();
|
||||
return this.setState({currentAsideTab: {}});
|
||||
}
|
||||
|
||||
this.setState({currentAsideTab: newTab});
|
||||
}
|
||||
|
||||
textEditorMdSize() {
|
||||
return this.state.currentAsideTab.label ? 7 : 10;
|
||||
changeEditorWidth(operation) {
|
||||
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() {
|
||||
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}>
|
||||
<TextEditorToolbarContainer openAsideTab={(newTab) => this.openAsideTab(newTab)}
|
||||
isContract={this.isContract()}
|
||||
currentFile={this.props.currentFile}
|
||||
activeTab={this.state.currentAsideTab}/>
|
||||
</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 sm={8} md={this.textEditorMdSize()} className="text-editor-container">
|
||||
<TextEditorContainer currentFile={this.props.currentFile} onFileContentChange={(newContent) => this.onFileContentChange(newContent)} />
|
||||
</Col>
|
||||
{this.state.currentAsideTab.label &&
|
||||
<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>}
|
||||
|
||||
{this.renderTextEditor()}
|
||||
|
||||
{this.state.currentAsideTab.label && this.renderAside()}
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
@ -95,6 +203,6 @@ EditorContainer.propTypes = {
|
|||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
{fetchEditorTabs: fetchEditorTabsAction.request},
|
||||
{fetchEditorTabs: fetchEditorTabsAction.request}
|
||||
)(EditorContainer);
|
||||
|
||||
|
|
|
@ -27,7 +27,10 @@ class TextEditorContainer extends React.Component {
|
|||
addEditorTabs={this.props.addEditorTabs}
|
||||
debuggerLine={this.props.debuggerLine}
|
||||
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,
|
||||
toggleBreakpoints: PropTypes.func,
|
||||
breakpoints: PropTypes.array,
|
||||
toggleBreakpoint: PropTypes.object,
|
||||
toggleBreakpoint: PropTypes.func,
|
||||
fetchEditorTabs: PropTypes.func,
|
||||
removeEditorTabs: PropTypes.func,
|
||||
addEditorTabs: PropTypes.func,
|
||||
|
@ -57,9 +60,11 @@ TextEditorContainer.propTypes = {
|
|||
export default connect(
|
||||
mapStateToProps,
|
||||
{
|
||||
toggleBreakpoint,
|
||||
toggleBreakpoint: toggleBreakpoint.request,
|
||||
fetchEditorTabs: fetchEditorTabsAction.request,
|
||||
removeEditorTabs: removeEditorTabsAction.request,
|
||||
addEditorTabs: addEditorTabsAction.request
|
||||
},
|
||||
null,
|
||||
{ withRef: true }
|
||||
)(TextEditorContainer);
|
||||
|
|
Loading…
Reference in New Issue