WIP: style fiddle
This commit is contained in:
parent
de901b73fc
commit
ea9939c03a
|
@ -0,0 +1,4 @@
|
|||
.fiddle--grid {
|
||||
margin-left: -30px;
|
||||
margin-right: -30px;
|
||||
}
|
|
@ -1,28 +1,27 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
Page,
|
||||
Grid
|
||||
} from "tabler-react";
|
||||
|
||||
import ApplicationPreviewContainer from '../containers/ApplicationPreviewContainer';
|
||||
import {Row, Col} from 'reactstrap';
|
||||
import TextEditorAsideContainer from '../containers/TextEditorAsideContainer';
|
||||
import TextEditorContainer from '../containers/TextEditorContainer';
|
||||
import FileExplorerContainer from '../containers/FileExplorerContainer';
|
||||
|
||||
import './FiddleLayout.css';
|
||||
|
||||
const DEFAULT_FILE = {name: 'newContract.sol', content: ''};
|
||||
|
||||
class FiddleLayout extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<Page.Content title="Fiddle">
|
||||
<Grid.Row className="my-5">
|
||||
<Grid.Col md={3}>
|
||||
<Page.Title>Fiddle</Page.Title>
|
||||
<FileExplorerContainer />
|
||||
</Grid.Col>
|
||||
<Grid.Col md={9}>
|
||||
<TextEditorContainer />
|
||||
</Grid.Col>
|
||||
</Grid.Row>
|
||||
<ApplicationPreviewContainer />
|
||||
</Page.Content>
|
||||
<Row noGutters className="h-100 fiddle--grid">
|
||||
<Col sm={4} md={2}>
|
||||
<FileExplorerContainer />
|
||||
</Col>
|
||||
<Col sm={8} md={6}>
|
||||
<TextEditorContainer defaultFile={DEFAULT_FILE} />
|
||||
</Col>
|
||||
<Col sm={12} md={4}>
|
||||
<TextEditorAsideContainer defaultFile={DEFAULT_FILE} />
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,85 @@ import PropTypes from 'prop-types';
|
|||
import {Treebeard, decorators} from 'react-treebeard';
|
||||
import {Form} from 'tabler-react';
|
||||
|
||||
const style = {
|
||||
tree: {
|
||||
base: {
|
||||
height: '100%',
|
||||
listStyle: 'none',
|
||||
backgroundColor: '#1C1C1C',
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
color: '#9DA5AB',
|
||||
fontFamily: 'lucida grande ,tahoma,verdana,arial,sans-serif',
|
||||
fontSize: '14px'
|
||||
},
|
||||
node: {
|
||||
base: {
|
||||
position: 'relative'
|
||||
},
|
||||
link: {
|
||||
cursor: 'pointer',
|
||||
position: 'relative',
|
||||
padding: '0px 5px',
|
||||
display: 'block'
|
||||
},
|
||||
activeLink: {
|
||||
background: '#31363F'
|
||||
},
|
||||
toggle: {
|
||||
base: {
|
||||
position: 'relative',
|
||||
display: 'inline-block',
|
||||
verticalAlign: 'top',
|
||||
marginLeft: '-5px',
|
||||
height: '24px',
|
||||
width: '24px'
|
||||
},
|
||||
wrapper: {
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
margin: '-7px 0 0 -7px',
|
||||
height: '14px'
|
||||
},
|
||||
height: 14,
|
||||
width: 14,
|
||||
arrow: {
|
||||
fill: '#9DA5AB',
|
||||
strokeWidth: 0
|
||||
}
|
||||
},
|
||||
header: {
|
||||
base: {
|
||||
display: 'inline-block',
|
||||
verticalAlign: 'top',
|
||||
color: '#9DA5AB'
|
||||
},
|
||||
connector: {
|
||||
width: '2px',
|
||||
height: '12px',
|
||||
borderLeft: 'solid 2px black',
|
||||
borderBottom: 'solid 2px black',
|
||||
position: 'absolute',
|
||||
top: '0px',
|
||||
left: '-21px'
|
||||
},
|
||||
title: {
|
||||
lineHeight: '24px',
|
||||
verticalAlign: 'middle'
|
||||
}
|
||||
},
|
||||
subtree: {
|
||||
listStyle: 'none',
|
||||
paddingLeft: '19px'
|
||||
},
|
||||
loading: {
|
||||
color: '#E2C089'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const Header = ({style, node}) => {
|
||||
const iconType = node.children ? 'folder' : 'file';
|
||||
const iconClass = `fe fe-${iconType}`;
|
||||
|
@ -104,6 +183,7 @@ class FileExplorer extends React.Component {
|
|||
data={this.filterHidden(this.props.files)}
|
||||
decorators={decorators}
|
||||
onToggle={this.onToggle.bind(this)}
|
||||
style={style}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
|
|
@ -66,7 +66,7 @@ const Layout = ({children, logout, credentials, location}) => (
|
|||
<AppSidebarMinimizer />
|
||||
</AppSidebar>
|
||||
<main className="main">
|
||||
<Container fluid>
|
||||
<Container fluid className="h-100">
|
||||
{children}
|
||||
</Container>
|
||||
</main>
|
||||
|
|
|
@ -2,37 +2,15 @@ import PropTypes from 'prop-types';
|
|||
import React from 'react';
|
||||
import {Form, Button} from 'tabler-react';
|
||||
|
||||
class ApplicationPreviewContainer extends React.Component {
|
||||
class Preview extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
previewUrl: this.props.previewHomepage
|
||||
previewUrl: this.props.previewUrl
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Form.Group>
|
||||
<Form.InputGroup>
|
||||
<Form.Input placeholder="URL"
|
||||
value={this.state.previewUrl}
|
||||
className="form-control"
|
||||
onChange={(e) => this.handlePreviewUrlChange(e)} />
|
||||
<Form.InputGroupAppend>
|
||||
<Button color="primary" onClick={(e) => this.handlePreviewGo(e)}>Go</Button>
|
||||
</Form.InputGroupAppend>
|
||||
</Form.InputGroup>
|
||||
<iframe width="100%"
|
||||
height="500"
|
||||
title="Preview"
|
||||
ref={(iframe) => this.previewIframe = iframe}
|
||||
onLoad={(e) => this.handlePreviewChange(e)} src={this.props.previewHomepage}>
|
||||
</iframe>
|
||||
</Form.Group>
|
||||
);
|
||||
}
|
||||
|
||||
handlePreviewUrlChange(ev) {
|
||||
this.setState({previewUrl: ev.target.value});
|
||||
}
|
||||
|
@ -41,23 +19,43 @@ class ApplicationPreviewContainer extends React.Component {
|
|||
try {
|
||||
let url = ev.target.contentWindow.location.toString();
|
||||
this.setState({previewUrl: url});
|
||||
} catch(e) {
|
||||
// Nothing here.
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
handlePreviewGo() {
|
||||
this.previewIframe.src = this.state.previewUrl;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Form.Group className='h-100'>
|
||||
<Form.InputGroup>
|
||||
<Form.Input placeholder="URL"
|
||||
value={this.state.previewUrl}
|
||||
className="form-control"
|
||||
onChange={(e) => this.handlePreviewUrlChange(e)} />
|
||||
<Form.InputGroupAppend>
|
||||
<Button color="primary" onClick={(e) => this.handlePreviewGo(e)}>Go</Button>
|
||||
</Form.InputGroupAppend>
|
||||
</Form.InputGroup>
|
||||
<iframe width="100%"
|
||||
height="100%"
|
||||
title="Preview"
|
||||
ref={(iframe) => this.previewIframe = iframe}
|
||||
onLoad={(e) => this.handlePreviewChange(e)} src={this.state.previewUrl}>
|
||||
</iframe>
|
||||
</Form.Group>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ApplicationPreviewContainer.propTypes = {
|
||||
previewHomepage: PropTypes.string
|
||||
Preview.propTypes = {
|
||||
previewUrl: PropTypes.string
|
||||
};
|
||||
|
||||
ApplicationPreviewContainer.defaultProps = {
|
||||
previewHomepage: window.location.protocol + '//' + window.location.host
|
||||
Preview.defaultProps = {
|
||||
previewUrl: window.location.protocol + '//' + window.location.host
|
||||
};
|
||||
|
||||
export default ApplicationPreviewContainer;
|
||||
export default Preview;
|
||||
|
|
@ -27,8 +27,13 @@ class TextEditor extends React.Component {
|
|||
const value = editor.getValue();
|
||||
this.props.onFileContentChange(value);
|
||||
});
|
||||
editor.layout();
|
||||
window.addEventListener('resize', this.handleResize);
|
||||
}
|
||||
|
||||
handleResize = () => editor.layout();
|
||||
|
||||
|
||||
getLanguage() {
|
||||
const extension = this.props.file.name.split('.').pop();
|
||||
return SUPPORTED_LANGUAGES[SUPPORTED_LANGUAGES.indexOf(extension)] || DEFAULT_LANGUAGE;
|
||||
|
@ -77,11 +82,10 @@ class TextEditor extends React.Component {
|
|||
|
||||
render() {
|
||||
const style = {
|
||||
width: "800px",
|
||||
height: "600px"
|
||||
height: "100%"
|
||||
};
|
||||
|
||||
return <div ref={this.assignRef} style={style} id={EDITOR_ID} />;
|
||||
return <div style={style} id={EDITOR_ID} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/* eslint multiline-ternary: "off" */
|
||||
/* eslint operator-linebreak: "off" */
|
||||
import React, {Component} from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
currentFile as currentFileAction,
|
||||
} from '../actions';
|
||||
import {getCurrentFile} from '../reducers/selectors';
|
||||
import Preview from '../components/Preview';
|
||||
|
||||
class TextEditorAsideContainer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {currentFile: this.props.currentFile};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.fetchCurrentFile();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if(this.props.currentFile.path !== prevProps.currentFile.path) {
|
||||
this.setState({currentFile: this.props.currentFile});
|
||||
}
|
||||
}
|
||||
|
||||
isContract() {
|
||||
return this.state.currentFile.name.endsWith('.sol');
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.isContract() ? <React.Fragment>hello</React.Fragment> : <Preview />
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state, props) {
|
||||
const currentFile = getCurrentFile(state) || props.defaultFile
|
||||
|
||||
return {
|
||||
currentFile,
|
||||
loading: state.loading,
|
||||
error: state.errorMessage
|
||||
};
|
||||
}
|
||||
|
||||
TextEditorAsideContainer.propTypes = {
|
||||
currentFile: PropTypes.object,
|
||||
fetchCurrentFile: PropTypes.func,
|
||||
loading: PropTypes.bool,
|
||||
error: PropTypes.string
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
{
|
||||
fetchCurrentFile: currentFileAction.request,
|
||||
},
|
||||
)(TextEditorAsideContainer);
|
|
@ -3,7 +3,6 @@
|
|||
import React, {Component} from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import {Grid} from 'tabler-react';
|
||||
import TextEditor from '../components/TextEditor';
|
||||
import TextEditorContractErrors from '../components/TextEditorContractErrors';
|
||||
import TextEditorContractWarnings from '../components/TextEditorContractWarnings';
|
||||
|
@ -20,8 +19,6 @@ import {
|
|||
} from '../actions';
|
||||
import {getCurrentFile, getContractCompile, getContractDeploys} from '../reducers/selectors';
|
||||
|
||||
const DEFAULT_FILE = {name: 'newContract.sol', content: ''};
|
||||
|
||||
class TextEditorContainer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
@ -62,7 +59,7 @@ class TextEditorContainer extends Component {
|
|||
|
||||
remove() {
|
||||
this.props.removeFile(this.state.currentFile);
|
||||
this.setState({currentFile: DEFAULT_FILE});
|
||||
this.setState({currentFile: this.props.defaultFile});
|
||||
}
|
||||
|
||||
renderContractFooter() {
|
||||
|
@ -103,21 +100,15 @@ class TextEditorContainer extends Component {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Grid.Row className="my-2">
|
||||
{this.renderToolbar()}
|
||||
</Grid.Row>
|
||||
<TextEditor file={this.state.currentFile}
|
||||
contractCompile={this.props.contractCompile}
|
||||
onFileContentChange={(newContent) => this.onFileContentChange(newContent)} />
|
||||
{this.renderContractFooter()}
|
||||
</React.Fragment>
|
||||
<TextEditor file={this.state.currentFile}
|
||||
contractCompile={this.props.contractCompile}
|
||||
onFileContentChange={(newContent) => this.onFileContentChange(newContent)} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const currentFile = getCurrentFile(state) || DEFAULT_FILE;
|
||||
function mapStateToProps(state, props) {
|
||||
const currentFile = getCurrentFile(state) || props.defaultFile;
|
||||
const contractCompile = getContractCompile(state, currentFile) || {};
|
||||
const contractName = contractCompile.result && Object.keys(contractCompile.result)[0];
|
||||
const contractDeploys = getContractDeploys(state, contractName);
|
||||
|
|
Loading…
Reference in New Issue