Beginning Draggability

This commit is contained in:
James Barnsley
2016-11-10 16:17:10 +13:00
parent 47377b5c78
commit 15c1d83440
12 changed files with 205 additions and 16 deletions

View File

@ -14,9 +14,6 @@ class ContextMenu extends React.Component{
super(props);
}
handleClick(e){
}
renderItems(){
var items = [];

68
src/js/components/Dragger.js Executable file
View File

@ -0,0 +1,68 @@
import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import * as uiActions from '../services/ui/actions'
import * as mopidyActions from '../services/mopidy/actions'
import * as spotifyActions from '../services/spotify/actions'
class Dragger extends React.Component{
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this)
this.handleMouseUp = this.handleMouseUp.bind(this)
}
componentDidMount(){
window.addEventListener("mousemove", this.handleMouseMove, false);
window.addEventListener("mouseup", this.handleMouseUp, false);
}
componentWillUnmount(){
window.removeEventListener("mousemove", this.handleMouseMove, false);
window.removeEventListener("mouseup", this.handleMouseUp, false);
}
handleMouseMove(e){
if( !this.props.dragger || !this.props.dragger.dragging ) return null;
this.props.uiActions.dragMove( e )
}
handleMouseUp(e){
if( !this.props.dragger || !this.props.dragger.dragging ) return null;
this.props.uiActions.dragEnd( e )
}
render(){
if( !this.props.dragger || !this.props.dragger.dragging ) return null;
var style = {
left: this.props.dragger.position_x,
top: this.props.dragger.position_y,
}
return (
<div className="dragger" style={style}>
Dragging { this.props.dragger.victims.length } things
</div>
);
}
}
const mapStateToProps = (state, ownProps) => {
return {
dragger: state.ui.dragger
}
}
const mapDispatchToProps = (dispatch) => {
return {
uiActions: bindActionCreators(uiActions, dispatch),
spotifyActions: bindActionCreators(spotifyActions, dispatch),
mopidyActions: bindActionCreators(mopidyActions, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Dragger)

View File

@ -18,6 +18,18 @@ class Sidebar extends React.Component{
super(props);
}
renderDropzones(){
if( !this.props.dragger || !this.props.dragger.dragging ) return null
return (
<div className="dropzones">
<div className="zone">
<div className="title">Zone</div>
</div>
</div>
)
}
render(){
return (
<aside>
@ -89,6 +101,8 @@ class Sidebar extends React.Component{
</nav>
{ this.renderDropzones() }
<MiniPlayer />
</aside>
@ -109,7 +123,8 @@ const mapStateToProps = (state, ownProps) => {
pusher_connected: state.pusher.connected,
spotify_connected: state.spotify.connected,
spotify_authorized: state.spotify.authorized,
current_track: state.ui.current_track
current_track: state.ui.current_track,
dragger: state.ui.dragger
}
}

View File

@ -23,6 +23,13 @@ export default class Track extends React.Component{
return this.props.handleDoubleClick(e);
}
handleDragStart(e){
// if we're not selected, perform click behavior [first] << this is assumed
if( !this.props.track.selected ) this.handleClick(e)
this.props.handleDragStart(e)
}
handleContextMenu(e){
e.preventDefault();
@ -44,9 +51,11 @@ export default class Track extends React.Component{
return (
<div
className={className}
onDoubleClick={ (e) => this.handleDoubleClick(e) }
onClick={ (e) => this.handleClick(e) }
onContextMenu={ (e) => this.handleContextMenu(e) }>
draggable='true'
onDragStart={ e => this.handleDragStart(e) }
onClick={ e => this.handleClick(e) }
onDoubleClick={ e => this.handleDoubleClick(e) }
onContextMenu={ e => this.handleContextMenu(e) }>
{ this.props.track.selected ? <FontAwesome name="check" className="select-state" fixedWidth /> : null }
<span className="col name">
{ track.name ? track.name : '-' }

View File

@ -2,11 +2,12 @@
import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import * as mopidyActions from '../services/mopidy/actions'
import * as uiActions from '../services/ui/actions'
import Track from './Track'
import * as mopidyActions from '../services/mopidy/actions'
import * as uiActions from '../services/ui/actions'
class TrackList extends React.Component{
constructor(props) {
@ -81,12 +82,16 @@ class TrackList extends React.Component{
this.setState({ tracks: tracks, lastSelectedTrack: index });
}
handleDoubleClick( e, index ){
handleDoubleClick(e, index){
if( this.props.context_menu.show ) this.props.uiActions.hideContextMenu();
this.playTracks()
}
handleContextMenu( e, index ){
handleDragStart(e, index){
this.props.uiActions.dragStart( e, 'tltracks', this.selectedTracks() )
}
handleContextMenu(e, index){
var data = {
selected_tracks: this.selectedTracks()
}
@ -148,9 +153,10 @@ class TrackList extends React.Component{
show_source_icon={ this.props.show_source_icon }
key={index+'_'+track.uri}
track={track}
handleDoubleClick={(e) => self.handleDoubleClick(e, index)}
handleClick={(e) => self.handleClick(e, index)}
handleContextMenu={(e) => self.handleContextMenu(e, index)} />
handleDoubleClick={ e => self.handleDoubleClick(e, index)}
handleClick={ e => self.handleClick(e, index)}
handleDragStart={ e => self.handleDragStart(e, index)}
handleContextMenu={ e => self.handleContextMenu(e, index)} />
}
)
}

View File

@ -12,7 +12,7 @@ const localstorageMiddleware = (function(){
// append our state to a global variable. This gives us access to debug the store at any point
window._store = store
console.log(action)
//console.log(action)
switch( action.type ){

View File

@ -39,4 +39,26 @@ export function lazyLoading( start ){
}
}
export function dragStart( e, context, victims ){
return {
type: 'DRAG_START',
context: context,
victims: victims,
position_x: e.clientX,
position_y: e.clientY
}
}
export function dragMove( e ){
return {
type: 'DRAG_MOVE',
position_x: e.clientX,
position_y: e.clientY,
}
}
export function dragEnd(){
return { type: 'DRAG_END' }
}

View File

@ -23,6 +23,40 @@ export default function reducer(ui = {}, action){
return Object.assign({}, ui, { context_menu: { show: false } });
/**
* Dragging
**/
case 'DRAG_START':
return Object.assign({}, ui, {
dragger: {
dragging: true,
context: action.context,
victims: action.victims,
position_x: action.position_x,
position_y: action.position_y
}
});
case 'DRAG_MOVE':
var dragger = Object.assign({}, ui.dragger, {
position_x: action.position_x,
position_y: action.position_y
})
return Object.assign({}, ui, { dragger: dragger });
case 'DRAG_END':
return Object.assign({}, ui, {
dragger: {
dragging: false,
context: false,
victims: false
}
});
/**
* Albums
**/

View File

@ -7,6 +7,7 @@ import { connect } from 'react-redux'
import Sidebar from '../components/Sidebar'
import ContextMenu from '../components/ContextMenu'
import Dragger from '../components/Dragger'
import * as uiActions from '../services/ui/actions'
import * as pusherActions from '../services/pusher/actions'
@ -93,13 +94,17 @@ class App extends React.Component{
}
render(){
var className = '';
if( this.props.dragger && this.props.dragger.dragging ) className += ' dragging'
return (
<div>
<div className={className}>
<Sidebar />
<main>
{this.props.children}
</main>
<ContextMenu state={this.props.context_menu} />
<Dragger />
</div>
);
}
@ -116,6 +121,7 @@ const mapStateToProps = (state, ownProps) => {
mopidy_connected: state.mopidy.connected,
spotify_authorized: state.spotify.authorized,
play_state: state.mopidy.play_state,
dragger: state.ui.dragger,
context_menu: state.ui.context_menu
}
}

View File

@ -8,6 +8,7 @@
@import 'global/forms';
@import 'components/context-menu';
@import 'components/dragger';
@import 'components/images';
@import 'components/icon';
@import 'components/search-form';

View File

@ -0,0 +1,30 @@
.dragger {
position: fixed;
left: 0;
top: 0;
z-index: 9999;
background: $blue;
color: #FFFFFF;
padding: 12px 20px;
pointer-events: none;
}
.dropzones {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 9998;
background: rgba(25, 25, 25, 0.9);
.zone {
margin: 15px;
padding: 50px 20px;
background: $turquoise;
color: #FFFFFF;
font-size: 16px;
text-align: center;
}
}

View File

@ -7,6 +7,7 @@ $dark_grey: #333333;
$secondary_grey: #888888;
$red: #cf2d2d;
$green: #47af2a;
$blue: #32b5f2;
@mixin one_line_text {
white-space: nowrap;