From d55f25f424a0904acc73def952f41b2e707de17b Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Thu, 29 Sep 2016 08:15:46 -0700 Subject: [PATCH] Progress --- css/page.css | 7 -- css/winamp.css | 5 -- js/components/DraggableWindow.jsx | 106 ------------------------- js/components/EqualizerWindow.jsx | 63 ++++++++------- js/components/MainWindow.jsx | 81 ++++++++++--------- js/components/PlaylistWindow.jsx | 6 +- js/components/WindowManager.jsx | 124 ++++++++++++++++++++++++++++++ js/index.js | 9 ++- js/media.js | 1 - js/reducers.js | 2 +- package.json | 1 + 11 files changed, 203 insertions(+), 202 deletions(-) delete mode 100644 js/components/DraggableWindow.jsx create mode 100644 js/components/WindowManager.jsx diff --git a/css/page.css b/css/page.css index 52244aea..cb3a9dd3 100644 --- a/css/page.css +++ b/css/page.css @@ -17,13 +17,6 @@ body { text-align: center; } -#main-window { - margin-top: -58px; - margin-left: -137px; - top: 40%; - left: 50%; -} - .about { position: absolute; bottom: 0; diff --git a/css/winamp.css b/css/winamp.css index 56ae36c5..d2174d04 100644 --- a/css/winamp.css +++ b/css/winamp.css @@ -1,9 +1,4 @@ /* Rules used by all windows */ -#winamp2-js { - height: 116px; - width: 275px; -} - /* Range input css reset */ #winamp2-js input[type=range]{ -webkit-appearance: none; margin: 0; padding: 0; background: none; border: none; } diff --git a/js/components/DraggableWindow.jsx b/js/components/DraggableWindow.jsx deleted file mode 100644 index d17ba620..00000000 --- a/js/components/DraggableWindow.jsx +++ /dev/null @@ -1,106 +0,0 @@ -import {cloneElement, Children, Component} from 'react'; -import {clamp} from '../utils'; - -const SNAP_DISTANCE = 15; - -// Many of the ideas of how to build this as a React componant were stolen -// from: https://github.com/mzabriskie/react-draggable Thanks! @mzabriskie -class DraggableWindow extends Component { - constructor(props) { - super(props); - this.handleMouseDown = this.handleMouseDown.bind(this); - this.state = {}; - } - - handleMouseDown(e) { - if (!e.target.classList.contains(this.props.handleClass)) { - // Prevent going into drag mode when clicking any of the title - // bar's icons by making sure the click was made directly on the - // handle - return true; - } - // If the element was 'absolutely' positioned we could simply use - // offsetLeft / offsetTop however the element is 'relatively' - // positioned so we're using style.left. parseInt is used to remove the - // 'px' postfix from the value - const winStart = { - left: parseInt(this.body.offsetLeft || 0, 10), - top: parseInt(this.body.offsetTop || 0, 10) - }; - const maxLeft = window.innerWidth - this.body.offsetWidth; - const maxTop = window.innerHeight - this.body.offsetHeight; - - // Get starting mouse position - const mouseStart = { - left: e.clientX, - top: e.clientY - }; - - // Mouse move handler function while mouse is down - const handleMove = (moveEvent) => { - // Calculate difference offsets between current and starting positions - const diff = { - left: moveEvent.clientX - mouseStart.left, - top: moveEvent.clientY - mouseStart.top - }; - - let left = winStart.left + diff.left; - let top = winStart.top + diff.top; - - // Snap to top - if (top < SNAP_DISTANCE) { - top = 0; - } - - // Snap to right - if (left > maxLeft - SNAP_DISTANCE) { - left = maxLeft; - } - - // Snap to left - if (left < SNAP_DISTANCE) { - left = 0; - } - - // Snap to bottom - if (top > maxTop - SNAP_DISTANCE) { - top = maxTop; - } - - // These margins were only useful for centering the div, now we - // don't need them - this.setState({ - marginLeft: '0px', - marginTop: '0px', - left: `${left}px`, - top: `${top}px`, - position: 'absolute' - }); - }; - - // Mouse button up - function handleUp() { - removeListeners(); - } - - function removeListeners() { - window.removeEventListener('mousemove', handleMove); - window.removeEventListener('mouseup', handleUp); - } - - window.addEventListener('mousemove', handleMove); - window.addEventListener('mouseup', handleUp); - return false; - } - render() { - const {children} = this.props; - return cloneElement(Children.only(children), { - ref: (body) => this.body = body, - onMouseDown: this.handleMouseDown, - style: {...children.props.style, ...this.state} - }); - } - -} - -module.exports = DraggableWindow; diff --git a/js/components/EqualizerWindow.jsx b/js/components/EqualizerWindow.jsx index 061d09e3..084f4c4a 100644 --- a/js/components/EqualizerWindow.jsx +++ b/js/components/EqualizerWindow.jsx @@ -11,7 +11,6 @@ import { setEqToMin } from '../actionCreators'; -import DraggableWindow from './DraggableWindow.jsx'; import Band from './Band.jsx'; import EqOn from './EqOn.jsx'; import EqAuto from './EqAuto.jsx'; @@ -47,40 +46,38 @@ class EqualizerWindow extends React.Component { doubled }); return ( - -
-
- - - -
+
+
+ + + +
+ +
+
+
+ {BANDS.map((hertz) => ( -
-
-
- {BANDS.map((hertz) => ( - - ))} -
- + ))} +
); } } diff --git a/js/components/MainWindow.jsx b/js/components/MainWindow.jsx index 9ef68895..50865642 100644 --- a/js/components/MainWindow.jsx +++ b/js/components/MainWindow.jsx @@ -10,7 +10,6 @@ import Close from './Close.jsx'; import ClutterBar from './ClutterBar.jsx'; import ContextMenu from './ContextMenu.jsx'; import DragTarget from './DragTarget.jsx'; -import DraggableWindow from './DraggableWindow.jsx'; import Eject from './Eject.jsx'; import EqToggleButton from './EqToggleButton.jsx'; import Kbps from './Kbps.jsx'; @@ -34,7 +33,7 @@ export class MainWindow extends React.Component { this.handleClick = this.handleClick.bind(this); } - handleClick() { + handleClick(e) { this.props.dispatch({type: 'SET_FOCUSED_WINDOW', window: WINDOWS.MAIN}); } @@ -66,47 +65,45 @@ export class MainWindow extends React.Component { // absolutely positioned, exists at a different location than the main // window. Drag/Drop still work, because events propogate up to parent // elements. - return - -
-
Loading...
-
- - -
- - -
-
- -
-
-
-
- - - - - - - -
- -
-
- - - -
- - -
- + return ( +
+
Loading...
+
+ + +
+ +
- - ; +
+ +
+
+
+
+ + + + + + + +
+ +
+
+ + + +
+ + +
+ +
+ ); } } diff --git a/js/components/PlaylistWindow.jsx b/js/components/PlaylistWindow.jsx index b34cfeff..cc93b7ff 100644 --- a/js/components/PlaylistWindow.jsx +++ b/js/components/PlaylistWindow.jsx @@ -1,8 +1,6 @@ import React from 'react'; import {connect} from 'react-redux'; -import DraggableWindow from './DraggableWindow.jsx'; - import '../../css/playlist-window.css'; const PlaylistWindow = (props) => { @@ -11,7 +9,7 @@ const PlaylistWindow = (props) => { style.color = props.Normal; style.backgroundColor = props.NormalBG; } - return + return (
@@ -31,7 +29,7 @@ const PlaylistWindow = (props) => {
-
; + ); }; module.exports = connect((state) => state.display.skinPlaylistStyle)(PlaylistWindow); diff --git a/js/components/WindowManager.jsx b/js/components/WindowManager.jsx new file mode 100644 index 00000000..f6516d7f --- /dev/null +++ b/js/components/WindowManager.jsx @@ -0,0 +1,124 @@ +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); + const state = {}; + this.validChildren().forEach((child, i) => { + state[i] = { + x: -(WINDOW_WIDTH / 2), + y: 0 + }; + }); + this.state = state; + this.windowNodes = []; + this.getRef = this.getRef.bind(this); + this.handleMouseDown = this.handleMouseDown.bind(this); + } + + 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) { + 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: '50vh', + left: '50vw' + }; + return ( +
+ {this.validChildren().map((child, i) => { + const position = this.state[i] || {}; + /* eslint-disable react/jsx-no-bind */ + return ( +
this.handleMouseDown(i, e)} + ref={this.getRef} + style={{...style, ...position}} + key={i} + > + {child} +
+ ); + /* eslint-enable react/jsx-no-bind */ + })} +
+ ); + } +} +module.exports = WindowManager; diff --git a/js/index.js b/js/index.js index 5190ccea..e4b2f27d 100644 --- a/js/index.js +++ b/js/index.js @@ -6,6 +6,7 @@ import thunk from 'redux-thunk'; import reducer from './reducers'; +import WindowManager from './components/WindowManager.jsx'; import Browser from './browser'; import MainWindow from './components/MainWindow.jsx'; import PlaylistWindow from './components/PlaylistWindow.jsx'; @@ -34,9 +35,11 @@ if (new Browser(window).isCompatible) { {/* This is not technically kosher, since