2017-11-15 00:46:02 +01:00
|
|
|
import React from 'react';
|
|
|
|
import PropTypes from 'proptypes';
|
|
|
|
import injectSheet from 'react-jss';
|
|
|
|
import { connect } from 'react-redux';
|
2017-11-23 15:56:04 +01:00
|
|
|
import * as actions from '../actions/index.js';
|
2017-11-15 00:46:02 +01:00
|
|
|
import Logo from './Logo.js';
|
|
|
|
import D2Panel from './D2Panel.js';
|
|
|
|
import D3Panel from './D3Panel.js';
|
|
|
|
import SketcherToolbars from './SketcherToolbars.js';
|
2017-11-15 15:13:49 +01:00
|
|
|
import Button from './Button.js';
|
|
|
|
import vlineImageURL from '../../img/vline.png';
|
|
|
|
import btnUndoImageURL from '../../img/mainmenu/btnUndo.png';
|
|
|
|
import btnRedoImageURL from '../../img/mainmenu/btnRedo.png';
|
2017-11-15 15:37:11 +01:00
|
|
|
import InlineIconsLoader from './InlineIconsLoader.js';
|
2017-11-23 16:07:54 +01:00
|
|
|
import JSONToSketchData from '../shape/JSONToSketchData.js';
|
2017-12-14 10:59:06 +01:00
|
|
|
import keycode from 'keycode';
|
|
|
|
import bowser from 'bowser';
|
|
|
|
import * as d2Tools from '../constants/d2Tools.js';
|
2018-02-21 11:54:25 +01:00
|
|
|
import { isLoaded, load } from '../utils/loaded.js';
|
2017-11-15 00:46:02 +01:00
|
|
|
|
|
|
|
const styles = {
|
|
|
|
container: {
|
2017-11-15 15:13:49 +01:00
|
|
|
position: 'relative',
|
|
|
|
userSelect: 'none',
|
2017-11-15 00:46:02 +01:00
|
|
|
display: 'flex',
|
|
|
|
flexDirection: 'column',
|
|
|
|
alignItems: 'stretch',
|
|
|
|
height: '100%'
|
|
|
|
},
|
|
|
|
appContainer: {
|
|
|
|
flexGrow: 1,
|
|
|
|
display: 'flex',
|
|
|
|
alignItems: 'stretch',
|
|
|
|
overflow: 'hidden'
|
|
|
|
},
|
|
|
|
vLine: {
|
|
|
|
backgroundSize: '14px auto',
|
|
|
|
backgroundImage: `url('${vlineImageURL}')`,
|
|
|
|
width: '28px'
|
|
|
|
},
|
|
|
|
undoMenu: {
|
|
|
|
display: 'flex',
|
|
|
|
position: 'absolute',
|
|
|
|
top: 0,
|
|
|
|
left: '50%',
|
|
|
|
marginLeft: '-68px'
|
|
|
|
},
|
|
|
|
undo: {
|
|
|
|
cursor: 'pointer',
|
|
|
|
backgroundSize: '68px auto',
|
|
|
|
width: '68px',
|
|
|
|
height: '58px',
|
|
|
|
backgroundImage: `url('${btnUndoImageURL}')`
|
|
|
|
},
|
|
|
|
redo: {
|
|
|
|
cursor: 'pointer',
|
|
|
|
backgroundSize: '71px auto',
|
|
|
|
width: '71px',
|
|
|
|
height: '58px',
|
|
|
|
backgroundImage: `url('${btnRedoImageURL}')`
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class App extends React.Component {
|
|
|
|
static propTypes = {
|
2017-11-23 15:56:04 +01:00
|
|
|
openSketch: PropTypes.func.isRequired,
|
|
|
|
addImage: PropTypes.func.isRequired,
|
2017-11-15 00:46:02 +01:00
|
|
|
undo: PropTypes.func.isRequired,
|
|
|
|
redo: PropTypes.func.isRequired,
|
2017-12-14 10:59:06 +01:00
|
|
|
classes: PropTypes.objectOf(PropTypes.string),
|
|
|
|
deleteSelection: PropTypes.func.isRequired,
|
|
|
|
selectAll: PropTypes.func.isRequired,
|
|
|
|
d2ChangeTool: PropTypes.func.isRequired,
|
|
|
|
moveSelection: PropTypes.func.isRequired,
|
|
|
|
selectedPen: PropTypes.string.isRequired
|
2017-11-15 00:46:02 +01:00
|
|
|
};
|
|
|
|
|
2018-02-21 11:54:25 +01:00
|
|
|
state = {
|
|
|
|
loaded: isLoaded()
|
|
|
|
};
|
|
|
|
|
2017-11-23 15:56:04 +01:00
|
|
|
componentDidMount() {
|
|
|
|
const { container } = this.refs;
|
|
|
|
|
2018-02-21 11:54:25 +01:00
|
|
|
if (!this.state.loaded) load.then(() => this.setState({ loaded: true }));
|
|
|
|
|
2017-11-23 15:56:04 +01:00
|
|
|
container.addEventListener('dragover', event => event.preventDefault());
|
|
|
|
container.addEventListener('drop', this.onDrop);
|
2017-12-14 10:59:06 +01:00
|
|
|
window.addEventListener('keydown', this.onKeyDown);
|
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
const { container } = this.refs;
|
|
|
|
container.removeEventListener('drop', this.onDrop);
|
|
|
|
window.removeEventListener('keydown', this.onKeyDown);
|
2017-11-23 15:56:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
onDrop = async event => {
|
|
|
|
const { openSketch, addImage } = this.props;
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
for (const file of event.dataTransfer.files) {
|
2017-12-13 17:25:42 +01:00
|
|
|
const extentions = file.name.split('.').pop();
|
2017-11-23 15:56:04 +01:00
|
|
|
|
2017-12-13 17:25:42 +01:00
|
|
|
switch (extentions.toUpperCase()) {
|
2017-11-23 15:56:04 +01:00
|
|
|
case 'D3SKETCH':
|
|
|
|
case 'JSON':
|
|
|
|
const url = URL.createObjectURL(file);
|
2018-02-21 12:29:33 +01:00
|
|
|
const json = await fetch(url).then(result => result.json());
|
|
|
|
const data = await JSONToSketchData(json);
|
|
|
|
openSketch({ data });
|
2017-11-23 15:56:04 +01:00
|
|
|
break;
|
|
|
|
case 'JPG':
|
|
|
|
case 'JPEG':
|
|
|
|
case 'PNG':
|
|
|
|
case 'GIF':
|
|
|
|
await addImage(file);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-12-14 10:59:06 +01:00
|
|
|
onKeyDown = (event) => {
|
|
|
|
const { undo, redo, deleteSelection, selectAll, d2ChangeTool, moveSelection, selectedPen } = this.props;
|
|
|
|
const { metaKey, ctrlKey, shiftKey } = event;
|
|
|
|
const key = keycode(event);
|
|
|
|
const commandKey = bowser.mac ? metaKey : ctrlKey;
|
|
|
|
|
|
|
|
const targetTag = event.target.tagName.toLowerCase();
|
|
|
|
if (targetTag === 'input' || targetTag === 'textarea') return;
|
|
|
|
|
|
|
|
switch (key) {
|
|
|
|
case 'backspace':
|
|
|
|
case 'delete':
|
|
|
|
event.preventDefault();
|
|
|
|
deleteSelection();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'a':
|
|
|
|
if (commandKey) selectAll();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'z':
|
|
|
|
if (commandKey) {
|
|
|
|
if (shiftKey) {
|
|
|
|
redo();
|
|
|
|
} else {
|
|
|
|
undo();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 't': {
|
|
|
|
if (!commandKey) d2ChangeTool(d2Tools.TEXT);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 'b': {
|
|
|
|
if (!commandKey) d2ChangeTool(selectedPen);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 'left':
|
|
|
|
case 'right':
|
|
|
|
case 'up':
|
|
|
|
case 'down': {
|
|
|
|
const delta = shiftKey ? 10 : 1;
|
|
|
|
const deltas = {
|
|
|
|
left: { deltaX: -delta, deltaY: 0 },
|
|
|
|
right: { deltaX: delta, deltaY: 0 },
|
|
|
|
up: { deltaX: 0, deltaY: -delta },
|
|
|
|
down: { deltaX: 0, deltaY: delta }
|
|
|
|
};
|
|
|
|
|
|
|
|
const { deltaX, deltaY } = deltas[key];
|
|
|
|
moveSelection(deltaX, deltaY);
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2017-11-23 15:56:04 +01:00
|
|
|
}
|
|
|
|
|
2017-11-15 00:46:02 +01:00
|
|
|
render() {
|
|
|
|
const { classes, undo, redo } = this.props;
|
2018-02-21 11:54:25 +01:00
|
|
|
const { loaded } = this.state;
|
|
|
|
|
2017-11-15 00:46:02 +01:00
|
|
|
return (
|
2017-11-23 15:56:04 +01:00
|
|
|
<div ref="container" className={classes.container}>
|
2017-11-15 15:37:11 +01:00
|
|
|
<InlineIconsLoader />
|
2018-02-21 11:54:25 +01:00
|
|
|
{loaded && <div className={classes.appContainer}>
|
2017-11-15 00:46:02 +01:00
|
|
|
<D2Panel />
|
|
|
|
<div className={classes.vLine} />
|
|
|
|
<D3Panel />
|
2018-02-21 11:54:25 +01:00
|
|
|
</div>}
|
2017-11-15 00:46:02 +01:00
|
|
|
<Logo />
|
|
|
|
<div className={classes.undoMenu}>
|
2017-11-15 15:13:49 +01:00
|
|
|
<Button onSelect={undo} className={classes.undo} />
|
|
|
|
<Button onSelect={redo} className={classes.redo} />
|
2017-11-15 00:46:02 +01:00
|
|
|
</div>
|
2017-11-15 15:13:49 +01:00
|
|
|
<SketcherToolbars />
|
2017-11-15 00:46:02 +01:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-14 10:59:06 +01:00
|
|
|
export default injectSheet(styles)(connect(state => ({
|
|
|
|
selectedPen: state.sketcher.present.menus['pen-tools'].selected
|
|
|
|
}), {
|
2017-11-15 00:46:02 +01:00
|
|
|
undo: actions.undo.undo,
|
2017-11-23 15:56:04 +01:00
|
|
|
redo: actions.undo.redo,
|
|
|
|
openSketch: actions.openSketch,
|
2017-12-14 10:59:06 +01:00
|
|
|
addImage: actions.addImage,
|
|
|
|
deleteSelection: actions.deleteSelection,
|
|
|
|
selectAll: actions.selectAll,
|
|
|
|
d2ChangeTool: actions.d2ChangeTool,
|
|
|
|
moveSelection: actions.moveSelection
|
2017-11-15 00:46:02 +01:00
|
|
|
})(App));
|