mirror of
https://github.com/captbaritone/webamp.git
synced 2026-07-21 17:18:52 +00:00
143 lines
3.5 KiB
JavaScript
143 lines
3.5 KiB
JavaScript
import React from 'react';
|
|
import {findDOMNode} from 'react-dom';
|
|
|
|
import {snapToMany, snapWithin, applySnap} from '../snapUtils';
|
|
|
|
const WINDOW_HEIGHT = 116;
|
|
const WINDOW_WIDTH = 275;
|
|
|
|
class WindowManager extends React.Component {
|
|
constructor(props) {
|
|
super(props);
|
|
this.windowNodes = [];
|
|
this.state = {};
|
|
this.getRef = this.getRef.bind(this);
|
|
this.handleMouseDown = this.handleMouseDown.bind(this);
|
|
}
|
|
|
|
componentDidMount() {
|
|
window.addEventListener('resize', this.centerWindows.bind(this));
|
|
const {innerHeight, innerWidth} = window;
|
|
if (innerHeight || innerWidth) {
|
|
this.centerWindows();
|
|
}
|
|
}
|
|
|
|
centerWindows() {
|
|
const {innerHeight, innerWidth} = window;
|
|
const state = {};
|
|
const children = this.validChildren();
|
|
const totalHeight = children.length * WINDOW_HEIGHT;
|
|
children.forEach((child, i) => {
|
|
const offset = WINDOW_HEIGHT * i;
|
|
state[i] = {
|
|
left: (innerWidth / 2) - WINDOW_WIDTH / 2,
|
|
top: (innerHeight / 2) - (totalHeight / 2) + offset
|
|
};
|
|
});
|
|
this.setState(state);
|
|
}
|
|
|
|
getRef(node) {
|
|
this.windowNodes.push(node);
|
|
}
|
|
|
|
otherWindows(element) {
|
|
const domNodes = this.windowNodes.map(findDOMNode);
|
|
return domNodes.filter((node) => node !== element);
|
|
}
|
|
|
|
nodeInfo(node) {
|
|
const child = node.childNodes[0];
|
|
const {height, width} = child.getBoundingClientRect();
|
|
const {offsetLeft, offsetTop} = node;
|
|
return {
|
|
x: offsetLeft,
|
|
y: offsetTop,
|
|
height,
|
|
width
|
|
};
|
|
}
|
|
|
|
handleMouseDown(i, e) {
|
|
if (!e.target.classList.contains('draggable')) {
|
|
return;
|
|
}
|
|
const mouseStart = {
|
|
x: e.clientX,
|
|
y: e.clientY
|
|
};
|
|
|
|
const windowStart = this.nodeInfo(e.currentTarget);
|
|
|
|
const otherWindowNodes = this.otherWindows(e.currentTarget).map(this.nodeInfo);
|
|
|
|
const browserSize = {
|
|
width: window.innerWidth,
|
|
height: window.innerHeight
|
|
};
|
|
|
|
const handleMouseMove = (ee) => {
|
|
const diff = {
|
|
x: ee.clientX - mouseStart.x,
|
|
y: ee.clientY - mouseStart.y
|
|
};
|
|
|
|
const proposedWindow = {
|
|
...windowStart,
|
|
x: windowStart.x + diff.x,
|
|
y: windowStart.y + diff.y
|
|
};
|
|
|
|
const snappedToOthers = snapToMany(proposedWindow, otherWindowNodes);
|
|
const snappedToBrowser = snapWithin(proposedWindow, browserSize);
|
|
|
|
const newPosition = applySnap(proposedWindow, snappedToBrowser, snappedToOthers);
|
|
|
|
this.setState({[i]: {top: newPosition.y, left: newPosition.x}});
|
|
};
|
|
|
|
window.addEventListener('mouseup', () => {
|
|
window.removeEventListener('mousemove', handleMouseMove);
|
|
});
|
|
window.addEventListener('mousemove', handleMouseMove);
|
|
}
|
|
|
|
validChildren() {
|
|
return React.Children.toArray(this.props.children).filter((child) => child);
|
|
}
|
|
|
|
render() {
|
|
const style = {
|
|
position: 'absolute'
|
|
};
|
|
|
|
const parentStyle = {
|
|
position: 'absolute',
|
|
width: 0,
|
|
height: 0,
|
|
top: 0,
|
|
left: 0
|
|
};
|
|
return (
|
|
<div style={parentStyle}>
|
|
{this.validChildren().map((child, i) => {
|
|
const position = this.state[i];
|
|
/* eslint-disable react/jsx-no-bind */
|
|
return position && (
|
|
<div
|
|
onMouseDown={(e) => this.handleMouseDown(i, e)}
|
|
ref={this.getRef}
|
|
style={{...style, ...position}}
|
|
key={i}
|
|
>
|
|
{child}
|
|
</div>
|
|
);
|
|
/* eslint-enable react/jsx-no-bind */
|
|
})}
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
module.exports = WindowManager;
|