Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added viewport resizer #17

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
dist
node_modulesi
node_modules/
*.log
4 changes: 2 additions & 2 deletions src/client/ui/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ export function getControls(data) {

export function getIframe(data) {
const iframeStyle = {
width: '100%',
width: 'calc(100% - 10px)', // minus manual resizer width
height: '100%',
border: '0',
border: '2px solid #e0e0e0',
};

// We need to send dataId via queryString
Expand Down
305 changes: 293 additions & 12 deletions src/client/ui/layout.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,90 @@
import React from 'react';
import ReactDOM from 'react-dom';
import SizeButton from './size-button';

const sizes = {
iphone4: {
width: 320,
height: 480,
},
samsungS5: {
width: 360,
height: 640,
},
iphone6: {
width: 375,
height: 667,
},
};

class Layout extends React.Component {
constructor(props) {
super(props);

this.state = {
isControlOpen: true,
isActionLoggerOpen: true,
isIframeCoverHidden: true,
viewportHeight: 500,
viewportWidth: 400,
origClientX: 0,
dragging: false,
};

this.toggleControls = this.toggleControls.bind(this);
this.toggleActionLogger = this.toggleActionLogger.bind(this);
this.toggleIframeCover = this.toggleIframeCover.bind(this);

this.updateHeight = this.updateHeight.bind(this);
this.updateViewportWidth = this.updateViewportWidth.bind(this);
this.updateViewportHeight = this.updateViewportHeight.bind(this);
this.updateOrigClientX = this.updateOrigClientX.bind(this);

this.handleOnMouseDownResizer = this.handleOnMouseDownResizer.bind(this);
this.handleOnMouseMove = this.handleOnMouseMove.bind(this);
this.handleOnMouseUp = this.handleOnMouseUp.bind(this);
this.handleOnChangeWidthInput = this.handleOnChangeWidthInput.bind(this);
this.handleOnChangeHeightInput = this.handleOnChangeHeightInput.bind(this);
this.handleOnClickSizeBtn = this.handleOnClickSizeBtn.bind(this);
}

componentWillMount() {
this.updateHeight();
}

componentDidMount() {
window.addEventListener('resize', this.updateHeight.bind(this));
window.addEventListener('mousemove', this.handleOnMouseMove);
window.addEventListener('mouseup', this.handleOnMouseUp);
window.addEventListener('resize', this.updateHeight);
}

componentWillUnmount() {
window.removeEventListener('mousemove', this.handleOnMouseMove);
window.removeEventListener('mouseup', this.handleOnMouseUp);
window.removeEventListener('resize', this.updateHeight);
}

updateViewportWidth(viewportWidth) {
/*
// so far i didn't any anomalies
// can be removed if there's no issue
const resizer = this.refs.manualResizer;
const resizerEl = ReactDOM.findDOMNode(resizer);
const currentXPos = resizerEl.getBoundingClientRect().left;
this.updateOrigClientX(currentXPos);
*/

this.setState({
viewportWidth,
});

return;
}

updateViewportHeight(viewportHeight) {
this.setState({
viewportHeight,
});
}

updateHeight() {
Expand All @@ -16,43 +94,246 @@ class Layout extends React.Component {
this.setState({ height });
}

updateOrigClientX(coord) {
this.setState({
origClientX: coord,
});
}

toggleControls() {
this.setState({
isControlOpen: !this.state.isControlOpen,
});
}

toggleActionLogger() {
this.setState({
isActionLoggerOpen: !this.state.isActionLoggerOpen,
});
}

toggleIframeCover() {
this.setState({
isIframeCoverHidden: !this.state.isIframeCoverHidden,
});
}

handleOnMouseDownResizer(event) {
this.updateOrigClientX(event.clientX);

// make cover visible so that mouse pointer doesn't
// go into iframe
this.toggleIframeCover();

this.setState({
dragging: true,
});
}

handleOnMouseMove(event) {
if (this.state.dragging) {
const currentPos = event.clientX;
const origPos = parseInt(this.state.origClientX);
const diffPos = currentPos - origPos;
const currentViewportWidth = parseInt(this.state.viewportWidth);
const newViewportWidth = currentViewportWidth + diffPos;

this.updateOrigClientX(currentPos);
this.updateViewportWidth(newViewportWidth);
}
}

handleOnMouseUp() {
if (this.state.dragging) {
// hide iframe cover to enable iframe interaction
this.toggleIframeCover();

this.setState({
dragging: false,
});
}
}

handleOnChangeWidthInput(event) {
this.updateViewportWidth(event.target.value);
}

handleOnChangeHeightInput(event) {
this.updateViewportHeight(event.target.value);
}

handleOnClickSizeBtn(size) {
const height = sizes[size].height;
const width = sizes[size].width;

this.updateViewportHeight(height);
this.updateViewportWidth(width);
}

render() {
const { controls, preview, actionLogger } = this.props;
const { height } = this.state;
const {
controls,
preview,
actionLogger,
} = this.props;

const {
height,
viewportWidth,
viewportHeight,
isControlOpen,
isActionLoggerOpen,
isIframeCoverHidden,
} = this.state;

const rootStyles = {
height,
padding: 8,
backgroundColor: '#F7F7F7',
};
const controlsStyle = {

let controlsStyle = {
position: 'fixed',
top: 0,
left: -240,
bottom: 0,
width: 240,
float: 'left',
height: '100%',
overflowY: 'auto',
};

const actionStyle = {
let actionStyle = {
position: 'fixed',
bottom: -150,
width: '100%',
height: 150,
marginLeft: 250,
};

const previewStyle = {
height: height - actionStyle.height - 25,
marginLeft: 250,
let previewStyle = {
height: height - 16,
border: '1px solid #ECECEC',
borderRadius: 4,
padding: 5,
backgroundColor: '#FFF',
};

const toggleStyle = {
display: 'block',
height: '36px',
overflow: 'hidden',
};

const iframeStyle = {
width: `${viewportWidth}px`,
height: `${viewportHeight}px`,
margin: '0 auto',
};

let iframeCoverStyle = {
display: 'initial',
position: 'fixed',
top: 0,
right: 0,
bottom: 0,
left: 0,
zIndex: 200,
};

const manualResizerStyle = {
width: '5px',
height: '100%',
backgroundColor: 'red',
borderTop: '2px solid red',
borderBottom: '2px solid red',
display: 'inline-block',
cursor: 'col-resize',
};

if (isControlOpen) {
controlsStyle = {
...controlsStyle,
left: 0,
};

actionStyle = {
...actionStyle,
marginLeft: 250,
};

previewStyle = {
...previewStyle,
marginLeft: 250,
};
}

if (isActionLoggerOpen) {
actionStyle = {
...actionStyle,
bottom: 0,
};

previewStyle = {
...previewStyle,
height: height - actionStyle.height - 16,
};
}

if (isIframeCoverHidden) {
iframeCoverStyle = {
...iframeCoverStyle,
display: 'none',
};
}

return (
<div style={rootStyles}>
<div style={controlsStyle}>
{controls}
</div>
<div style={previewStyle}>
{preview}
<div style={toggleStyle}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we move these button set into a seperate component?

<input
type="number"
value={viewportWidth}
placeholder="width"
onChange={this.handleOnChangeWidthInput}
/>
<input
type="number"
value={viewportHeight}
placeholder="height"
onChange={this.handleOnChangeHeightInput}
/>
<button onClick={this.toggleControls}>
toggle controls
</button>
<button onClick={this.toggleActionLogger}>
toggle action
</button>
<SizeButton
type="iphone4"
label="iPhone 4"
onClick={this.handleOnClickSizeBtn}
/>
<SizeButton
type="samsungS5"
label="Samsung S5"
onClick={this.handleOnClickSizeBtn}
/>
<SizeButton
type="iphone6"
label="iPhone 6"
onClick={this.handleOnClickSizeBtn}
/>
</div>
<div style={iframeCoverStyle}></div>
<div style={iframeStyle}>
{preview}
<div
ref="manualResizer"
style={manualResizerStyle}
onMouseDown={this.handleOnMouseDownResizer}
></div>
</div>
</div>
<div style={actionStyle}>
{actionLogger}
Expand Down
27 changes: 27 additions & 0 deletions src/client/ui/size-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React, { PropTypes } from 'react';

/**
* proxy component
*/

const propTypes = {
type: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
onClick: PropTypes.func.isRequired,
};

const SizeButton = ({
type,
label,
onClick,
}) => {
const onClickBtn = () => (onClick(type));

return (
<button onClick={onClickBtn}>{label}</button>
);
};

SizeButton.propTypes = propTypes;

export default SizeButton;