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 React from 'react';
import { import {Row, Col} from 'reactstrap';
Page, import TextEditorAsideContainer from '../containers/TextEditorAsideContainer';
Grid
} from "tabler-react";
import ApplicationPreviewContainer from '../containers/ApplicationPreviewContainer';
import TextEditorContainer from '../containers/TextEditorContainer'; import TextEditorContainer from '../containers/TextEditorContainer';
import FileExplorerContainer from '../containers/FileExplorerContainer'; import FileExplorerContainer from '../containers/FileExplorerContainer';
import './FiddleLayout.css';
const DEFAULT_FILE = {name: 'newContract.sol', content: ''};
class FiddleLayout extends React.Component { class FiddleLayout extends React.Component {
render() { render() {
return ( return (
<Page.Content title="Fiddle"> <Row noGutters className="h-100 fiddle--grid">
<Grid.Row className="my-5"> <Col sm={4} md={2}>
<Grid.Col md={3}> <FileExplorerContainer />
<Page.Title>Fiddle</Page.Title> </Col>
<FileExplorerContainer /> <Col sm={8} md={6}>
</Grid.Col> <TextEditorContainer defaultFile={DEFAULT_FILE} />
<Grid.Col md={9}> </Col>
<TextEditorContainer /> <Col sm={12} md={4}>
</Grid.Col> <TextEditorAsideContainer defaultFile={DEFAULT_FILE} />
</Grid.Row> </Col>
<ApplicationPreviewContainer /> </Row>
</Page.Content>
); );
} }
} }

View File

@ -3,6 +3,85 @@ import PropTypes from 'prop-types';
import {Treebeard, decorators} from 'react-treebeard'; import {Treebeard, decorators} from 'react-treebeard';
import {Form} from 'tabler-react'; 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 Header = ({style, node}) => {
const iconType = node.children ? 'folder' : 'file'; const iconType = node.children ? 'folder' : 'file';
const iconClass = `fe fe-${iconType}`; const iconClass = `fe fe-${iconType}`;
@ -104,6 +183,7 @@ class FileExplorer extends React.Component {
data={this.filterHidden(this.props.files)} data={this.filterHidden(this.props.files)}
decorators={decorators} decorators={decorators}
onToggle={this.onToggle.bind(this)} onToggle={this.onToggle.bind(this)}
style={style}
/> />
</React.Fragment> </React.Fragment>
); );

View File

@ -66,7 +66,7 @@ const Layout = ({children, logout, credentials, location}) => (
<AppSidebarMinimizer /> <AppSidebarMinimizer />
</AppSidebar> </AppSidebar>
<main className="main"> <main className="main">
<Container fluid> <Container fluid className="h-100">
{children} {children}
</Container> </Container>
</main> </main>

View File

@ -2,37 +2,15 @@ import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import {Form, Button} from 'tabler-react'; import {Form, Button} from 'tabler-react';
class ApplicationPreviewContainer extends React.Component { class Preview extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { 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) { handlePreviewUrlChange(ev) {
this.setState({previewUrl: ev.target.value}); this.setState({previewUrl: ev.target.value});
} }
@ -41,23 +19,43 @@ class ApplicationPreviewContainer extends React.Component {
try { try {
let url = ev.target.contentWindow.location.toString(); let url = ev.target.contentWindow.location.toString();
this.setState({previewUrl: url}); this.setState({previewUrl: url});
} catch(e) { } catch(e) {}
// Nothing here.
}
} }
handlePreviewGo() { handlePreviewGo() {
this.previewIframe.src = this.state.previewUrl; 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 = { Preview.propTypes = {
previewHomepage: PropTypes.string previewUrl: PropTypes.string
}; };
ApplicationPreviewContainer.defaultProps = { Preview.defaultProps = {
previewHomepage: window.location.protocol + '//' + window.location.host 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(); const value = editor.getValue();
this.props.onFileContentChange(value); this.props.onFileContentChange(value);
}); });
editor.layout();
window.addEventListener('resize', this.handleResize);
} }
handleResize = () => editor.layout();
getLanguage() { getLanguage() {
const extension = this.props.file.name.split('.').pop(); const extension = this.props.file.name.split('.').pop();
return SUPPORTED_LANGUAGES[SUPPORTED_LANGUAGES.indexOf(extension)] || DEFAULT_LANGUAGE; return SUPPORTED_LANGUAGES[SUPPORTED_LANGUAGES.indexOf(extension)] || DEFAULT_LANGUAGE;
@ -77,11 +82,10 @@ class TextEditor extends React.Component {
render() { render() {
const style = { const style = {
width: "800px", height: "100%"
height: "600px"
}; };
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 React, {Component} from 'react';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import {Grid} from 'tabler-react';
import TextEditor from '../components/TextEditor'; import TextEditor from '../components/TextEditor';
import TextEditorContractErrors from '../components/TextEditorContractErrors'; import TextEditorContractErrors from '../components/TextEditorContractErrors';
import TextEditorContractWarnings from '../components/TextEditorContractWarnings'; import TextEditorContractWarnings from '../components/TextEditorContractWarnings';
@ -20,8 +19,6 @@ import {
} from '../actions'; } from '../actions';
import {getCurrentFile, getContractCompile, getContractDeploys} from '../reducers/selectors'; import {getCurrentFile, getContractCompile, getContractDeploys} from '../reducers/selectors';
const DEFAULT_FILE = {name: 'newContract.sol', content: ''};
class TextEditorContainer extends Component { class TextEditorContainer extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
@ -62,7 +59,7 @@ class TextEditorContainer extends Component {
remove() { remove() {
this.props.removeFile(this.state.currentFile); this.props.removeFile(this.state.currentFile);
this.setState({currentFile: DEFAULT_FILE}); this.setState({currentFile: this.props.defaultFile});
} }
renderContractFooter() { renderContractFooter() {
@ -103,21 +100,15 @@ class TextEditorContainer extends Component {
render() { render() {
return ( return (
<React.Fragment> <TextEditor file={this.state.currentFile}
<Grid.Row className="my-2"> contractCompile={this.props.contractCompile}
{this.renderToolbar()} onFileContentChange={(newContent) => this.onFileContentChange(newContent)} />
</Grid.Row>
<TextEditor file={this.state.currentFile}
contractCompile={this.props.contractCompile}
onFileContentChange={(newContent) => this.onFileContentChange(newContent)} />
{this.renderContractFooter()}
</React.Fragment>
); );
} }
} }
function mapStateToProps(state) { function mapStateToProps(state, props) {
const currentFile = getCurrentFile(state) || DEFAULT_FILE; const currentFile = getCurrentFile(state) || props.defaultFile;
const contractCompile = getContractCompile(state, currentFile) || {}; const contractCompile = getContractCompile(state, currentFile) || {};
const contractName = contractCompile.result && Object.keys(contractCompile.result)[0]; const contractName = contractCompile.result && Object.keys(contractCompile.result)[0];
const contractDeploys = getContractDeploys(state, contractName); const contractDeploys = getContractDeploys(state, contractName);