Skip to content

Commit

Permalink
Move layout editing to its own component with toolbar to add/remove
Browse files Browse the repository at this point in the history
  • Loading branch information
noahm committed Oct 18, 2018
1 parent 100e33b commit fc7b630
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 48 deletions.
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"files.exclude": {
"**/node_modules": true
}
}
9 changes: 6 additions & 3 deletions frontend/src/common-styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,19 @@ div {
margin: 0px;
}
button {
background-color: rebeccapurple;
background-color: #6441a4;
border-radius: 0;
border: none;
border: 1px solid transparent;
outline: none;
color: white;
cursor: pointer;
transition: background-color 0.2s ease;
margin: 0.5em;
padding: 0.5em 1rem;
}
button:hover {
background-color: rgb(126, 86, 165);
background-color: #7d5bbe;
border-color: #7d5bbe;
}
button:disabled, input:disabled {
opacity: 0.6;
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/config/follow-button.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ svg {
user-select: none;
pointer-events: none;
box-shadow: grey 0 0 3px;
margin: 0;
padding: 0;
}

.button:hover {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/config/follow-zone.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class FollowZone extends Component {
};
return (
<div className={styles.followZone} style={style} ref={this.root} onMouseDown={this.onMoveStart}>
Click here to follow John
Click here to follow {this.props.children}
<div className={styles.resizeHandle} onMouseDown={this.onResizeStart} />
</div>
);
Expand Down
47 changes: 3 additions & 44 deletions frontend/src/config/index.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
import '../common-styles.css';
import styles from './config.css';
import { applyThemeClass } from '../common-styles';
import { FollowButton } from './follow-button';
import { Component, CSSProperties } from 'react';
import { Component } from 'react';
import { render } from 'react-dom';
import Dropzone from 'react-dropzone';
import Draggable from 'react-draggable';
import { FollowZone } from './follow-zone';
import { LayoutEditor } from './layout-editor';

class App extends Component {
state = {};

render() {
return (
<div style={{ fontSize: '200%' }}>
Expand All @@ -26,45 +20,10 @@ class App extends Component {
on the button, or manually input your own.
</p>
</div>
<div>
<Dropzone accept="image/*" disableClick multiple={false} onDrop={this.onDrop} style={this.getDropzoneStyles()}>
<div style={{ height: '720px', width: '1280px', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
{this.state.background ? <img src={this.state.background} style={{ height: '100%' }} /> : <div>Drop an image of your stream layout here</div>}
<div style={{ position: "absolute", height: '100%', width: '100%' }}>
<Draggable bounds="parent" defaultClassName={styles.draggable} defaultClassNameDragging={styles.dragging}>
<div><FollowButton>Me</FollowButton></div>
</Draggable>
<FollowZone />
</div>
</div>
</Dropzone>
</div>
<LayoutEditor />
</div>
);
}

/** @return {CSSProperties} */
getDropzoneStyles() {
return {
border: '2px #666 dotted',
borderRadius: '5px',
display: 'inline-block',
};
}

onDrop = (files) => {
if (!files || !files.length) {
return;
}
const file = files[0];
const reader = new FileReader();
reader.onload = () => {
this.setState({
background: reader.result,
});
}
reader.readAsDataURL(file);
}
}

const appNode = document.createElement('div');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
.draggable {
display: inline-block;
position: absolute;
cursor: grab;
}

.draggable:hover {
box-shadow: 0px 0px 4px grey;
}

.dragging {
cursor: grabbing;
}
114 changes: 114 additions & 0 deletions frontend/src/config/layout-editor.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { Component, CSSProperties, ChangeEvent } from 'react';
import Dropzone from 'react-dropzone';
import Draggable from 'react-draggable';
import { FollowZone } from './follow-zone';
import { FollowButton } from './follow-button';
import styles from './layout-editor.css';

export class LayoutEditor extends Component {
state = {
background: undefined,
layout: [
{ type: 'button', top: 0, left: 0 },
{ type: 'zone', top: 50, left: 50, height: 25, width: 25 },
],
};
startingCharCode = 'A'.charCodeAt(0);

render() {
return (
<div>
<div>
<button onClick={this.addButton}>Add Button</button>
<button onClick={this.addZone}>Add Zone</button>
<select value="initial" onChange={this.handleDelete}>
<option value="initial" disabled>Delete...</option>
{this.state.layout.map((item, i) => {
const label = String.fromCharCode(this.startingCharCode + i);
return <option key={label} value={i}>{label}</option>
})}
</select>
</div>
<Dropzone accept="image/*" disableClick multiple={false} onDrop={this.onDrop} style={this.getDropzoneStyles()}>
<div style={{ height: '720px', width: '1280px', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
{this.state.background ? <img src={this.state.background} style={{ height: '100%' }} /> : <div>Drop an image of your stream layout here</div>}
<div style={{ position: "absolute", height: '100%', width: '100%' }}>
{this.state.layout.map((item, i) => {
const label = String.fromCharCode(this.startingCharCode + i);
if (item.type === 'button') {
return (
<Draggable key={label} bounds="parent" defaultClassName={styles.draggable} defaultClassNameDragging={styles.dragging} defaultPosition={{ x: item.left, y: item.top }}>
<div><FollowButton>{label}</FollowButton></div>
</Draggable>
);
} else {
return <FollowZone key={label}>{label}</FollowZone>;
}
})}
</div>
</div>
</Dropzone>
</div>
);
}

/**
* @param {ChangeEvent<HTMLSelectElement>} e
*/
handleDelete = (e) => {
const deleteIndex = +e.currentTarget.value;
if (!Number.isInteger(deleteIndex)) {
return;
}
this.setState((s) => {
const layout = s.layout.slice();
layout.splice(deleteIndex, 1);
return {
layout,
};
})
}

addButton = () => {
this.setState((s) => {
const layout = s.layout.slice();
layout.push({ type: 'button', top: 0, left: 0 });
return {
layout,
};
});
}

addZone = () => {
this.setState((s) => {
const layout = s.layout.slice();
layout.push({ type: 'zone', top: 0, left: 0, height: 25, width: 25 });
return {
layout,
};
});
}

/** @return {CSSProperties} */
getDropzoneStyles() {
return {
border: '2px #666 dotted',
borderRadius: '5px',
display: 'inline-block',
};
}

onDrop = (files) => {
if (!files || !files.length) {
return;
}
const file = files[0];
const reader = new FileReader();
reader.onload = () => {
this.setState({
background: reader.result,
});
}
reader.readAsDataURL(file);
}
}

0 comments on commit fc7b630

Please sign in to comment.