WIP: style fiddle

This commit is contained in:
Anthony Laibe 2018-10-11 12:08:47 +01:00 committed by Pascal Precht
parent de901b73fc
commit ea9939c03a
No known key found for this signature in database
GPG Key ID: 0EE28D8D6FD85D7D
8 changed files with 204 additions and 69 deletions

View File

@ -0,0 +1,4 @@
.fiddle--grid {
margin-left: -30px;
margin-right: -30px;
}

View File

@ -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>
<Row noGutters className="h-100 fiddle--grid">
<Col sm={4} md={2}>
<FileExplorerContainer />
</Grid.Col>
<Grid.Col md={9}>
<TextEditorContainer />
</Grid.Col>
</Grid.Row>
<ApplicationPreviewContainer />
</Page.Content>
</Col>
<Col sm={8} md={6}>
<TextEditorContainer defaultFile={DEFAULT_FILE} />
</Col>
<Col sm={12} md={4}>
<TextEditorAsideContainer defaultFile={DEFAULT_FILE} />
</Col>
</Row>
);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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