mirror of
https://github.com/captbaritone/webamp.git
synced 2026-07-19 09:33:47 +00:00
Progress
This commit is contained in:
parent
785af97700
commit
d55f25f424
11 changed files with 203 additions and 202 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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 (
|
||||
<DraggableWindow handleClass='title-bar'>
|
||||
<div id='equalizer-window' className={className} onClick={this.props.focusWindow}>
|
||||
<div className='equalizer-top title-bar' />
|
||||
<EqOn />
|
||||
<EqAuto />
|
||||
<EqGraph />
|
||||
<div id='presets' />
|
||||
<div id='equalizer-window' className={className} onClick={this.props.focusWindow}>
|
||||
<div className='equalizer-top title-bar' />
|
||||
<EqOn />
|
||||
<EqAuto />
|
||||
<EqGraph />
|
||||
<div id='presets' />
|
||||
<Band
|
||||
id='preamp'
|
||||
band='preamp'
|
||||
onChange={this.props.setPreampValue(this.props.mediaPlayer)}
|
||||
/>
|
||||
<div
|
||||
id='plus12db'
|
||||
onClick={this.props.setEqToMax(this.props.mediaPlayer)}
|
||||
/>
|
||||
<div
|
||||
id='zerodb'
|
||||
onClick={this.props.setEqToMid(this.props.mediaPlayer)}
|
||||
/>
|
||||
<div
|
||||
id='minus12db'
|
||||
onClick={this.props.setEqToMin(this.props.mediaPlayer)}
|
||||
/>
|
||||
{BANDS.map((hertz) => (
|
||||
<Band
|
||||
id='preamp'
|
||||
band='preamp'
|
||||
onChange={this.props.setPreampValue(this.props.mediaPlayer)}
|
||||
key={hertz}
|
||||
id={bandClassName(hertz)}
|
||||
band={hertz}
|
||||
onChange={this.setHertzValue(hertz)}
|
||||
/>
|
||||
<div
|
||||
id='plus12db'
|
||||
onClick={this.props.setEqToMax(this.props.mediaPlayer)}
|
||||
/>
|
||||
<div
|
||||
id='zerodb'
|
||||
onClick={this.props.setEqToMid(this.props.mediaPlayer)}
|
||||
/>
|
||||
<div
|
||||
id='minus12db'
|
||||
onClick={this.props.setEqToMin(this.props.mediaPlayer)}
|
||||
/>
|
||||
{BANDS.map((hertz) => (
|
||||
<Band
|
||||
key={hertz}
|
||||
id={bandClassName(hertz)}
|
||||
band={hertz}
|
||||
onChange={this.setHertzValue(hertz)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</DraggableWindow>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <DragTarget handleFiles={handleDrop}>
|
||||
<DraggableWindow handleClass='title-bar'>
|
||||
<div id='main-window' className={className} onClick={this.handleClick}>
|
||||
<div id='loading'>Loading...</div>
|
||||
<div id='title-bar' className='selected title-bar'>
|
||||
<ContextMenu mediaPlayer={this.props.mediaPlayer} winamp={this.props.winamp} />
|
||||
<ShadeTime />
|
||||
<div id='minimize' />
|
||||
<Shade />
|
||||
<Close mediaPlayer={this.props.mediaPlayer} />
|
||||
</div>
|
||||
<div className='status'>
|
||||
<ClutterBar />
|
||||
<div id='play-pause' />
|
||||
<div id='work-indicator' className={classnames({selected: this.props.display.working})} />
|
||||
<Time />
|
||||
<Visualizer analyser={this.props.mediaPlayer._analyser}/>
|
||||
</div>
|
||||
<div className='media-info'>
|
||||
<Marquee />
|
||||
<Kbps />
|
||||
<Khz />
|
||||
<MonoStereo />
|
||||
</div>
|
||||
<Volume mediaPlayer={this.props.mediaPlayer} />
|
||||
<Balance mediaPlayer={this.props.mediaPlayer} />
|
||||
<div className='windows'>
|
||||
<EqToggleButton />
|
||||
<div id='playlist-button' />
|
||||
</div>
|
||||
<Position mediaPlayer={this.props.mediaPlayer} />
|
||||
<ActionButtons mediaPlayer={this.props.mediaPlayer} />
|
||||
<Eject winamp={this.props.winamp} />
|
||||
<div className='shuffle-repeat'>
|
||||
<Shuffle mediaPlayer={this.props.mediaPlayer} />
|
||||
<Repeat mediaPlayer={this.props.mediaPlayer} />
|
||||
</div>
|
||||
<a id='about' target='blank' href='https://github.com/captbaritone/winamp2-js' />
|
||||
return (
|
||||
<div id='main-window' className={className} onClick={this.handleClick} onMouseDown={this.props.startDrag}>
|
||||
<div id='loading'>Loading...</div>
|
||||
<div id='title-bar' className='selected title-bar'>
|
||||
<ContextMenu mediaPlayer={this.props.mediaPlayer} winamp={this.props.winamp} />
|
||||
<ShadeTime />
|
||||
<div id='minimize' />
|
||||
<Shade />
|
||||
<Close mediaPlayer={this.props.mediaPlayer} />
|
||||
</div>
|
||||
</DraggableWindow>
|
||||
</DragTarget>;
|
||||
<div className='status'>
|
||||
<ClutterBar />
|
||||
<div id='play-pause' />
|
||||
<div id='work-indicator' className={classnames({selected: this.props.display.working})} />
|
||||
<Time />
|
||||
<Visualizer analyser={this.props.mediaPlayer._analyser}/>
|
||||
</div>
|
||||
<div className='media-info'>
|
||||
<Marquee />
|
||||
<Kbps />
|
||||
<Khz />
|
||||
<MonoStereo />
|
||||
</div>
|
||||
<Volume mediaPlayer={this.props.mediaPlayer} />
|
||||
<Balance mediaPlayer={this.props.mediaPlayer} />
|
||||
<div className='windows'>
|
||||
<EqToggleButton />
|
||||
<div id='playlist-button' />
|
||||
</div>
|
||||
<Position mediaPlayer={this.props.mediaPlayer} />
|
||||
<ActionButtons mediaPlayer={this.props.mediaPlayer} />
|
||||
<Eject winamp={this.props.winamp} />
|
||||
<div className='shuffle-repeat'>
|
||||
<Shuffle mediaPlayer={this.props.mediaPlayer} />
|
||||
<Repeat mediaPlayer={this.props.mediaPlayer} />
|
||||
</div>
|
||||
<a id='about' target='blank' href='https://github.com/captbaritone/winamp2-js' />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <DraggableWindow handleClass='title-bar'>
|
||||
return (
|
||||
<div id='playlist-window' className='window' style={style}>
|
||||
<div className='playlist-left'>
|
||||
<div className='playlist-right'>
|
||||
|
|
@ -31,7 +29,7 @@ const PlaylistWindow = (props) => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DraggableWindow>;
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = connect((state) => state.display.skinPlaylistStyle)(PlaylistWindow);
|
||||
|
|
|
|||
124
js/components/WindowManager.jsx
Normal file
124
js/components/WindowManager.jsx
Normal file
|
|
@ -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 (
|
||||
<div style={parentStyle}>
|
||||
{this.validChildren().map((child, i) => {
|
||||
const position = this.state[i] || {};
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
return (
|
||||
<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;
|
||||
|
|
@ -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 <style> tags should be in
|
||||
the <head>, but browsers don't really care... */}
|
||||
</Skin>
|
||||
<MainWindow winamp={winamp} mediaPlayer={winamp.media} />
|
||||
{ playlist ? <PlaylistWindow /> : '' }
|
||||
{ equalizer ? <EqualizerWindow mediaPlayer={winamp.media} /> : '' }
|
||||
<WindowManager>
|
||||
<MainWindow winamp={winamp} mediaPlayer={winamp.media} />
|
||||
{ playlist ? <PlaylistWindow /> : '' }
|
||||
{ equalizer ? <EqualizerWindow mediaPlayer={winamp.media} /> : '' }
|
||||
</WindowManager>
|
||||
</div>
|
||||
</Provider>,
|
||||
document.getElementById('winamp2-js')
|
||||
|
|
|
|||
|
|
@ -208,7 +208,6 @@ module.exports = {
|
|||
|
||||
// From 0-1
|
||||
setPreamp: function(value) {
|
||||
console.log('preamp', value);
|
||||
this._preamp.gain.value = value / 100;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ const windows = (state, action) => {
|
|||
if (!state) {
|
||||
return {
|
||||
focused: WINDOWS.MAIN,
|
||||
equalizer: false
|
||||
equalizer: true
|
||||
};
|
||||
}
|
||||
switch (action.type) {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
"serve": "webpack-dev-server",
|
||||
"weight": "npm run build && gzip-size built/winamp.js | pretty-bytes",
|
||||
"test": "jest && npm run lint",
|
||||
"tdd": "jest --watch",
|
||||
"deploy": "ssh jordaneldredge.com sh < deploy.sh"
|
||||
},
|
||||
"repository": {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue