feat(cockpit): make editor resizable

This commit is contained in:
Jonathan Rainville 2018-11-08 14:48:17 -05:00
parent a714e078c4
commit 1030607813
8 changed files with 166 additions and 29 deletions

View File

@ -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",

View File

@ -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",

View File

@ -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>

View File

@ -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}

View File

@ -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
};

View File

@ -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;
}

View File

@ -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);

View File

@ -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);