Adding sidebar list
This commit is contained in:
@ -1,22 +1,23 @@
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import Icon from './Icon';
|
||||
|
||||
export default memo((props) => {
|
||||
export default memo(({
|
||||
className = '',
|
||||
onTrigger,
|
||||
}) => {
|
||||
const handleClick = (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
props.onTrigger(e);
|
||||
onTrigger(e);
|
||||
};
|
||||
|
||||
let className = 'context-menu-trigger mouse-contextable touch-contextable';
|
||||
if (props.className) {
|
||||
className += ` ${props.className}`;
|
||||
}
|
||||
|
||||
return (
|
||||
<span className={className} onClick={handleClick}>
|
||||
<button
|
||||
className={`button button--icon button--default context-menu-trigger mouse-contextable touch-contextable ${className}`}
|
||||
onClick={handleClick}
|
||||
type="button"
|
||||
>
|
||||
<Icon name="more_horiz" />
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
});
|
||||
|
||||
@ -1,70 +1,44 @@
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import * as coreActions from '../../services/core/actions';
|
||||
import Icon from '../Icon';
|
||||
|
||||
class PinButton extends React.Component {
|
||||
remove = () => {
|
||||
const {
|
||||
coreActions: {
|
||||
removePinned,
|
||||
},
|
||||
uri,
|
||||
} = this.props;
|
||||
removePinned(uri);
|
||||
}
|
||||
const PinButton = ({
|
||||
uri,
|
||||
className,
|
||||
}) => {
|
||||
if (!uri) return null;
|
||||
|
||||
add = () => {
|
||||
const {
|
||||
coreActions: {
|
||||
addPinned,
|
||||
},
|
||||
uri,
|
||||
} = this.props;
|
||||
addPinned(uri);
|
||||
}
|
||||
const {
|
||||
removePinned,
|
||||
addPinned,
|
||||
} = coreActions;
|
||||
|
||||
render = () => {
|
||||
const {
|
||||
uri,
|
||||
isPinned,
|
||||
} = this.props;
|
||||
let { className = '' } = this.props;
|
||||
if (!uri) return null;
|
||||
const dispatch = useDispatch();
|
||||
const isPinned = useSelector((state) => state.core.pinned ? state.core.pinned.find((item) => item === uri) : false)
|
||||
const remove = () => dispatch(removePinned(uri));
|
||||
const add = () => dispatch(addPinned(uri));
|
||||
|
||||
className += ' button button--discrete';
|
||||
|
||||
if (isPinned) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className={`${className} button--destructive`}
|
||||
onClick={this.remove}
|
||||
>
|
||||
<Icon name="bookmark" />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
if (isPinned) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className={`${className} button--default`}
|
||||
onClick={this.add}
|
||||
className={`${className} button button--icon button--default`}
|
||||
onClick={remove}
|
||||
>
|
||||
<Icon name="bookmark_border" />
|
||||
<Icon name="star" />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className={`${className} button button--icon button--default`}
|
||||
onClick={add}
|
||||
>
|
||||
<Icon name="star_border" />
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state, { uri }) => ({
|
||||
isPinned: state.core.pinned ? state.core.pinned.find((item) => item === uri) : false,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
coreActions: bindActionCreators(coreActions, dispatch),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(PinButton);
|
||||
export default PinButton;
|
||||
|
||||
32
src/js/components/Fields/PinList.js
Executable file
32
src/js/components/Fields/PinList.js
Executable file
@ -0,0 +1,32 @@
|
||||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import Link from '../Link';
|
||||
|
||||
const PinList = () => {
|
||||
const uris = useSelector((state) => state.core.pinned || []);
|
||||
const playlists = useSelector((state) => state.core.playlists);
|
||||
|
||||
if (uris.length <= 0) return null;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{
|
||||
uris.map((uri) => {
|
||||
const playlist = playlists[uri] || { uri };
|
||||
return (
|
||||
<Link
|
||||
to={`/playlist/${uri}`}
|
||||
className="sidebar__menu__item sidebar__menu__item--submenu"
|
||||
activeClassName="sidebar__menu__item--active"
|
||||
key={uri}
|
||||
>
|
||||
{playlist.name || playlist.uri}
|
||||
</Link>
|
||||
);
|
||||
})
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PinList;
|
||||
@ -6,6 +6,7 @@ import { withRouter } from 'react-router';
|
||||
import Link from './Link';
|
||||
import Icon from './Icon';
|
||||
import Dropzones from './Fields/Dropzones';
|
||||
import PinList from './Fields/PinList';
|
||||
import * as uiActions from '../services/ui/actions';
|
||||
import * as mopidyActions from '../services/mopidy/actions';
|
||||
import { I18n, i18n } from '../locale';
|
||||
@ -80,7 +81,7 @@ class Sidebar extends React.Component {
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
render = () => {
|
||||
const {
|
||||
history,
|
||||
spotify_available,
|
||||
@ -134,6 +135,7 @@ class Sidebar extends React.Component {
|
||||
<Icon name="queue_music" type="material" />
|
||||
<I18n path="sidebar.playlists" />
|
||||
</Link>
|
||||
<PinList />
|
||||
<Link to="/library/artists" history={history} className="sidebar__menu__item" activeClassName="sidebar__menu__item--active">
|
||||
<Icon name="recent_actors" type="material" />
|
||||
<I18n path="sidebar.artists" />
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
|
||||
import { createRange } from '../../util/arrays';
|
||||
import { createRange, removeDuplicates } from '../../util/arrays';
|
||||
import { uriSource } from '../../util/helpers';
|
||||
|
||||
const spotifyActions = require('../../services/spotify/actions');
|
||||
@ -442,6 +442,6 @@ export function removePinned(uri) {
|
||||
export function updatePinned(pinned) {
|
||||
return {
|
||||
type: 'UPDATE_PINNED',
|
||||
pinned,
|
||||
pinned: removeDuplicates(pinned),
|
||||
};
|
||||
}
|
||||
|
||||
@ -814,7 +814,7 @@ const CoreMiddleware = (function () {
|
||||
]));
|
||||
next(action);
|
||||
break;
|
||||
|
||||
|
||||
case 'REMOVE_PINNED':
|
||||
store.dispatch(coreActions.updatePinned(
|
||||
store.getState().core.pinned.filter((item) => item !== action.uri),
|
||||
|
||||
@ -324,23 +324,11 @@
|
||||
}
|
||||
|
||||
.context-menu-trigger {
|
||||
display: inline-block;
|
||||
padding: 14px 12px;
|
||||
cursor: pointer;
|
||||
vertical-align: top;
|
||||
margin-top: 2px;
|
||||
position: relative;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
|
||||
.actions & {
|
||||
font-size: 24px;
|
||||
padding: 2px 10px 1px;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: colour(blue) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
|
||||
@ -15,28 +15,21 @@
|
||||
@include noselect();
|
||||
|
||||
&--material {
|
||||
font-family: 'Material Icons';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
line-height: 1;
|
||||
text-transform: none;
|
||||
letter-spacing: normal;
|
||||
word-wrap: normal;
|
||||
white-space: nowrap;
|
||||
direction: ltr;
|
||||
font-family: 'Material Icons';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
line-height: 1;
|
||||
text-transform: none;
|
||||
letter-spacing: normal;
|
||||
word-wrap: normal;
|
||||
white-space: nowrap;
|
||||
direction: ltr;
|
||||
vertical-align: top;
|
||||
font-size: 1.3em;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
font-feature-settings: 'liga';
|
||||
}
|
||||
|
||||
&--fontawesome {
|
||||
|
||||
}
|
||||
|
||||
&--svg {
|
||||
font-size: 1.3em;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
font-feature-settings: 'liga';
|
||||
}
|
||||
|
||||
&--spin {
|
||||
|
||||
@ -63,6 +63,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
&--submenu {
|
||||
font-size: 1rem;
|
||||
padding: 0.6em 0.7em;
|
||||
font-weight: 400 !important;
|
||||
margin: 0 1.1em 0 3em;
|
||||
|
||||
&:before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.sidebar__menu__item--active {
|
||||
background: transparent;
|
||||
color: colour(turquoise) !important;
|
||||
}
|
||||
}
|
||||
|
||||
&--active {
|
||||
background: colour(turquoise);
|
||||
color: colour(white) !important;
|
||||
|
||||
@ -253,6 +253,21 @@ select {
|
||||
padding: 16px 50px 14px;
|
||||
}
|
||||
|
||||
&--icon {
|
||||
padding: 0.2rem;
|
||||
font-size: 1.4rem;
|
||||
border: none;
|
||||
box-shadow: none !important;
|
||||
|
||||
&:hover {
|
||||
color: colour(blue) !important;
|
||||
}
|
||||
|
||||
.icon {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
&--pull-right {
|
||||
margin-right: 0;
|
||||
margin-left: 30px;
|
||||
|
||||
Reference in New Issue
Block a user