Redo context menus

This commit is contained in:
Jordan Eldredge 2017-09-16 14:04:13 -07:00
parent 02d9fa6da0
commit 1680e1b2fb
12 changed files with 95 additions and 229 deletions

View file

@ -1,5 +1,11 @@
#winamp2-js .doubled #context-menu {
-moz-transform: scale(0.5);
-moz-transform-origin: top left;
-webkit-transform: scale(0.5);
-webkit-transform-origin: top left;
}
#winamp2-js #context-menu {
display: none;
left: 0px;
}
@ -11,11 +17,7 @@
top: 0px;
}
#winamp2-js div:active > div > #context-menu {
display: block;
}
#winamp2-js .selected > #context-menu {
#winamp2-js .selected #context-menu {
display: block;
}
@ -43,6 +45,7 @@
padding: 1px 18px 3px 18px;
display: block;
}
#winamp2-js #context-menu li.parent:after {
float: right;
content: "\25b8";

View file

@ -112,7 +112,7 @@
left: 40px;
}
#winamp2-js #presets {
#winamp2-js #presets-context {
position: absolute;
width: 44px;
height: 12px;
@ -120,6 +120,11 @@
left: 217px;
}
#winamp2-js #presets {
width: 100%;
height: 100%;
}
#winamp2-js #eqGraph {
position: absolute;
width: 113px;

View file

@ -12,19 +12,6 @@
-ms-interpolation-mode: nearest-neighbor; /* IE (non-standard property) */
}
#winamp2-js #main-window.doubled #context-menu {
-moz-transform: scale(0.5);
-moz-transform-origin: top left;
-webkit-transform: scale(0.5);
-webkit-transform-origin: top left;
}
#winamp2-js #main-window.loading {
background-image: none;
background-color: #ffffff;
border: 2px solid #dddddd;
}
#winamp2-js #loading {
color: white;
text-align: center;
@ -92,7 +79,7 @@
cursor: url("../cursors/TITLEBAR.PNG"), auto;
}
#winamp2-js #option,
#winamp2-js #option-context,
#winamp2-js #minimize,
#winamp2-js #shade,
#winamp2-js #close {
@ -104,6 +91,11 @@
}
#winamp2-js #title-bar #option {
width: 100%;
height: 100%;
}
#winamp2-js #title-bar #option-context {
left: 6px;
}
#winamp2-js #title-bar #minimize {

View file

@ -1,7 +1,5 @@
export const LOAD_AUDIO_URL = "LOAD_AUDIO_URL";
export const LOAD_AUDIO_FILE = "LOAD_AUDIO_FILE";
export const CLOSE_CONTEXT_MENU = "CLOSE_CONTEXT_MENU";
export const CLOSE_PRESETS_CONTEXT_MENU = "CLOSE_PRESETS_CONTEXT_MENU";
export const CLOSE_WINAMP = "CLOSE_WINAMP";
export const CLOSE_EQUALIZER_WINDOW = "CLOSE_EQUALIZER_WINDOW";
export const IS_PLAYING = "IS_PLAYING";
@ -24,8 +22,6 @@ export const START_WORKING = "START_WORKING";
export const STEP_MARQUEE = "STEP_MARQUEE";
export const STOP = "STOP";
export const STOP_WORKING = "STOP_WORKING";
export const TOGGLE_CONTEXT_MENU = "TOGGLE_CONTEXT_MENU";
export const TOGGLE_PRESETS_CONTEXT_MENU = "TOGGLE_PRESET_CONTEXT_MENU";
export const TOGGLE_DOUBLESIZE_MODE = "TOGGLE_DOUBLESIZE_MODE";
export const TOGGLE_EQUALIZER_WINDOW = "TOGGLE_EQUALIZER_WINDOW";
export const TOGGLE_PLAYLIST_WINDOW = "TOGGLE_PLAYLIST_WINDOW";

View file

@ -37,28 +37,56 @@ Node.propTypes = {
};
export class ContextMenu extends React.Component {
componentWillMount() {
// Clicking anywhere outside the context menu will close the window
document.addEventListener("click", this.props.closeMenu);
constructor(props) {
super(props);
this.state = { selected: false };
this._handleHandleClick = this._handleHandleClick.bind(this);
this._handleGlobalClick = this._handleGlobalClick.bind(this);
}
componantWillUnmount() {
document.removeEventListener("click", this.props.closeMenu);
componentDidMount() {
document.addEventListener("click", this._handleGlobalClick);
}
componentWillUnmount() {
document.removeEventListener("click", this._handleGlobalClick);
}
_handleHandleClick() {
this.setState({ selected: !this.state.selected });
}
_handleGlobalClick(e) {
if (this.state.selected && !this.handleNode.contains(e.target)) {
this.setState({ selected: false });
}
}
render() {
const { selected, top, bottom, children } = this.props;
const { handle, children, top, bottom, ...passThroughProps } = this.props;
return (
<div className={classnames({ selected, top, bottom })}>
<ul id="context-menu">{children}</ul>
<div {...passThroughProps}>
<div
className="handle"
style={{ width: "100%", height: "100%" }}
ref={node => (this.handleNode = node)}
onClick={this._handleHandleClick}
>
{handle}
</div>
{this.state.selected && (
<div className={classnames({ top, bottom })}>
<ul id="context-menu">{children}</ul>
</div>
)}
</div>
);
}
}
ContextMenu.propTypes = {
closeMenu: PropTypes.func.isRequired,
children: PropTypes.any.isRequired,
handle: PropTypes.any.isRequired,
top: PropTypes.bool,
bottom: PropTypes.bool
};

View file

@ -1,18 +1,16 @@
import React from "react";
import { connect } from "react-redux";
import { CLOSE_PRESETS_CONTEXT_MENU } from "../../actionTypes";
import { openFileDialog, downloadPreset } from "../../actionCreators";
import { ContextMenu, Node } from "../ContextMenu";
const MainContextMenu = props => (
<ContextMenu closeMenu={props.closeMenu} selected={props.selected} top>
<ContextMenu top id="presets-context" handle={<div id="presets" />}>
<Node onClick={props.openFileDialog} label="Load" />
<Node onClick={props.downloadPreset} label="Save" />
</ContextMenu>
);
const mapDispatchToProps = (dispatch, ownProps) => ({
closeMenu: () => dispatch({ type: CLOSE_PRESETS_CONTEXT_MENU }),
openFileDialog: () => dispatch(openFileDialog(ownProps.fileInput)),
downloadPreset: () => dispatch(downloadPreset())
});

View file

@ -35,28 +35,21 @@ exports[`EqualizerWindow renders to snapshot 1`] = `
width="152"
/>
<div
id="presets"
onClick={[Function]}
id="presets-context"
>
<div
className="top"
className="handle"
onClick={[Function]}
style={
Object {
"height": "100%",
"width": "100%",
}
}
>
<ul
id="context-menu"
>
<li
label="Load"
onClick={[Function]}
>
Load
</li>
<li
label="Save"
onClick={[Function]}
>
Save
</li>
</ul>
<div
id="presets"
/>
</div>
</div>
<div

View file

@ -17,10 +17,7 @@ import {
toggleEqualizerShadeMode
} from "../../actionCreators";
import {
SET_FOCUSED_WINDOW,
TOGGLE_PRESETS_CONTEXT_MENU
} from "../../actionTypes";
import { SET_FOCUSED_WINDOW } from "../../actionTypes";
import Band from "./Band";
import EqOn from "./EqOn";
@ -71,12 +68,7 @@ const EqualizerWindow = props => {
<EqOn />
<EqAuto />
<EqGraph />
<div id="presets" onClick={props.togglePresetsContextMenu}>
<PresetsContextMenu
selected={props.contextMenuSelected}
fileInput={props.fileInput}
/>
</div>
<PresetsContextMenu fileInput={props.fileInput} />
<Band id="preamp" band="preamp" onChange={props.setPreampValue} />
<div id="plus12db" onClick={props.setEqToMax} />
<div id="zerodb" onClick={props.setEqToMid} />
@ -109,12 +101,6 @@ const mapDispatchToProps = dispatch => ({
setEqToMid: () => dispatch(setEqToMid()),
setEqToMax: () => dispatch(setEqToMax()),
setHertzValue: hertz => value => dispatch(setEqBand(hertz, value)),
togglePresetsContextMenu: e => {
dispatch({ type: TOGGLE_PRESETS_CONTEXT_MENU });
// TODO: Consider binding to a ref instead.
// https://stackoverflow.com/a/24421834
e.nativeEvent.stopImmediatePropagation();
},
closeEqualizerWindow: () => dispatch(closeEqualizerWindow()),
toggleEqualizerShadeMode: () => dispatch(toggleEqualizerShadeMode())
});
@ -122,7 +108,6 @@ const mapDispatchToProps = dispatch => ({
const mapStateToProps = state => ({
doubled: state.display.doubled,
selected: state.windows.focused === WINDOWS.EQUALIZER,
contextMenuSelected: state.presetsContextMenu.selected,
shade: state.display.equalizerShade,
volume: state.media.volume,
balance: state.media.balance

View file

@ -1,6 +1,5 @@
import React from "react";
import { connect } from "react-redux";
import { CLOSE_CONTEXT_MENU, TOGGLE_CONTEXT_MENU } from "../../actionTypes";
import {
close,
setSkinFromFilename,
@ -19,10 +18,9 @@ const SKINS = [
const MainContextMenu = props => (
<ContextMenu
closeMenu={props.closeMenu}
openMenu={props.openMenu}
selected={props.selected}
id="option-context"
bottom
handle={<div id="option" title="Winamp Menu" />}
>
<LinkNode
href="https://github.com/captbaritone/winamp2-js"
@ -49,17 +47,8 @@ const MainContextMenu = props => (
const mapDispatchToProps = (dispatch, ownProps) => ({
close: () => dispatch(close()),
closeMenu: () => {
dispatch({ type: CLOSE_CONTEXT_MENU });
},
openMenu: () => {
dispatch({ type: TOGGLE_CONTEXT_MENU });
},
openFileDialog: () => dispatch(openFileDialog(ownProps.fileInput)),
setSkin: filename => dispatch(setSkinFromFilename(filename))
});
export default connect(
state => ({ selected: state.contextMenu.selected }),
mapDispatchToProps
)(MainContextMenu);
export default connect(null, mapDispatchToProps)(MainContextMenu);

View file

@ -14,102 +14,22 @@ exports[`MainWindow renders to snapshot 1`] = `
id="title-bar"
>
<div
id="option"
onClick={[Function]}
title="Winamp Menu"
id="option-context"
>
<div
className="bottom"
className="handle"
onClick={[Function]}
style={
Object {
"height": "100%",
"width": "100%",
}
}
>
<ul
id="context-menu"
>
<li>
<a
href="https://github.com/captbaritone/winamp2-js"
label="Winamp2-js"
target="_blank"
>
Winamp2-js
</a>
</li>
<li
className="hr"
>
<hr />
</li>
<li
label="Play File..."
onClick={[Function]}
>
Play File...
</li>
<li
className="parent"
>
<ul>
<li
label="Load Skin..."
onClick={[Function]}
>
Load Skin...
</li>
<li
className="hr"
>
<hr />
</li>
<li
label="<Base Skin>"
onClick={[Function]}
>
&lt;Base Skin&gt;
</li>
<li
label="Mac OSX v1.5 (Aqua)"
onClick={[Function]}
>
Mac OSX v1.5 (Aqua)
</li>
<li
label="TopazAmp"
onClick={[Function]}
>
TopazAmp
</li>
<li
label="Vizor"
onClick={[Function]}
>
Vizor
</li>
<li
label="XMMS Turquoise "
onClick={[Function]}
>
XMMS Turquoise
</li>
<li
label="Zaxon Remake"
onClick={[Function]}
>
Zaxon Remake
</li>
</ul>
Skins
</li>
<li
className="hr"
>
<hr />
</li>
<li
label="Exit"
onClick={[Function]}
>
Exit
</li>
</ul>
<div
id="option"
title="Winamp Menu"
/>
</div>
</div>
<div

View file

@ -26,7 +26,7 @@ import Time from "./Time";
import Visualizer from "./Visualizer";
import MainVolume from "./MainVolume";
import { SET_FOCUSED_WINDOW, TOGGLE_CONTEXT_MENU } from "../../actionTypes";
import { SET_FOCUSED_WINDOW } from "../../actionTypes";
import { loadFileFromReference } from "../../actionCreators";
@ -40,7 +40,7 @@ export class MainWindow extends React.Component {
}
handleClick() {
this.props.dispatch({ type: SET_FOCUSED_WINDOW, window: WINDOWS.MAIN });
this.props.setFocus();
}
supress(e) {
@ -90,9 +90,7 @@ export class MainWindow extends React.Component {
onDrop={this.handleDrop}
>
<div id="title-bar" className="selected title-bard draggable">
<div id="option" onClick={this.props.toggleMenu} title="Winamp Menu">
<MainContextMenu fileInput={this.props.fileInput} />
</div>
<MainContextMenu fileInput={this.props.fileInput} />
{shade && <MiniTime />}
<div id="minimize" />
<Shade />
@ -148,12 +146,8 @@ const mapStateToProps = state => {
};
const mapDispatchToProps = dispatch => ({
toggleMenu: e => {
dispatch({ type: TOGGLE_CONTEXT_MENU });
// TODO: Consider binding to a ref instead.
// https://stackoverflow.com/a/24421834
e.nativeEvent.stopImmediatePropagation();
},
dispatch
setFocus: () => {
dispatch({ type: SET_FOCUSED_WINDOW, window: WINDOWS.MAIN });
}
});
export default connect(mapStateToProps, mapDispatchToProps)(MainWindow);

View file

@ -1,8 +1,6 @@
import { combineReducers } from "redux";
import { BANDS, WINDOWS } from "./constants";
import {
CLOSE_CONTEXT_MENU,
CLOSE_PRESETS_CONTEXT_MENU,
CLOSE_WINAMP,
SET_BALANCE,
SET_BAND_VALUE,
@ -17,8 +15,6 @@ import {
START_WORKING,
STEP_MARQUEE,
STOP_WORKING,
TOGGLE_CONTEXT_MENU,
TOGGLE_PRESETS_CONTEXT_MENU,
TOGGLE_DOUBLESIZE_MODE,
TOGGLE_EQUALIZER_WINDOW,
CLOSE_EQUALIZER_WINDOW,
@ -137,37 +133,6 @@ const display = (state = defaultDisplayState, action) => {
}
};
const defaultContextMenuState = {
selected: false
};
const contextMenu = (state = defaultContextMenuState, action) => {
switch (action.type) {
case TOGGLE_CONTEXT_MENU:
return { ...state, selected: !state.selected };
case CLOSE_CONTEXT_MENU:
return { ...state, selected: false };
default:
return state;
}
};
const presetsContextMenu = (state, action) => {
if (!state) {
return {
selected: false
};
}
switch (action.type) {
case TOGGLE_PRESETS_CONTEXT_MENU:
return { ...state, selected: !state.selected };
case CLOSE_PRESETS_CONTEXT_MENU:
return { ...state, selected: false };
default:
return state;
}
};
const equalizer = (state, action) => {
if (!state) {
state = {
@ -255,8 +220,6 @@ const reducer = combineReducers({
userInput,
windows,
display,
contextMenu,
presetsContextMenu,
equalizer,
media
});