Dropdown fields
This commit is contained in:
17
src/js/components/Fields/SelectField.js
Normal file
17
src/js/components/Fields/SelectField.js
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
import React from 'react';
|
||||
import Icon from '../Icon';
|
||||
|
||||
const SelectField = ({ onChange, value, options }) => (
|
||||
<div className="select-field">
|
||||
<select
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
value={value}
|
||||
>
|
||||
{options.map((option) => <option value={option.value}>{option.label}</option>)}
|
||||
</select>
|
||||
<Icon name="arrow_drop_down" className="select-field__icon" />
|
||||
</div>
|
||||
);
|
||||
|
||||
export default SelectField;
|
||||
@ -7,7 +7,7 @@ import VolumeControl from './Fields/VolumeControl';
|
||||
import MuteControl from './Fields/MuteControl';
|
||||
import LatencyControl from './Fields/LatencyControl';
|
||||
import TextField from './Fields/TextField';
|
||||
import Icon from './Icon';
|
||||
import SelectField from './Fields/SelectField';
|
||||
|
||||
import * as helpers from '../helpers';
|
||||
|
||||
@ -56,18 +56,14 @@ const SnapcastClients = ({ actions, group, groups, show_disconnected_clients })
|
||||
Group
|
||||
</div>
|
||||
<div className="input">
|
||||
<select onChange={(e) => actions.setClientGroup(client.id, e.target.value)} value={group.id}>
|
||||
{
|
||||
groups.map((group) => (
|
||||
<option value={group.id} key={group.id}>
|
||||
{group.name ? group.name : `Group ${group.id.substring(0, 3)}`}
|
||||
</option>
|
||||
))
|
||||
}
|
||||
<option value={group.id}>
|
||||
New group
|
||||
</option>
|
||||
</select>
|
||||
<SelectField
|
||||
onChange={(value) => actions.setClientGroup(client.id, value)}
|
||||
value={group.id}
|
||||
options={[
|
||||
...groups.map((group) => ({ value: group.id, label: group.name })),
|
||||
{ value: group.id, label: 'New group' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</label>
|
||||
<div className="snapcast__client__volume field">
|
||||
@ -83,6 +79,7 @@ const SnapcastClients = ({ actions, group, groups, show_disconnected_clients })
|
||||
<VolumeControl
|
||||
className="snapcast__volume-control snapcast__client__volume-control"
|
||||
volume={client.volume}
|
||||
mute={client.mute}
|
||||
onVolumeChange={(percent) => actions.setClientVolume(client.id, percent)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -12,6 +12,7 @@ import Link from './Link';
|
||||
|
||||
import * as helpers from '../helpers';
|
||||
import * as actions from '../services/snapcast/actions';
|
||||
import SelectField from './Fields/SelectField';
|
||||
|
||||
const SnapcastGroups = (props) => {
|
||||
const {
|
||||
@ -64,19 +65,13 @@ const SnapcastGroups = (props) => {
|
||||
Stream
|
||||
</div>
|
||||
<div className="input">
|
||||
<select onChange={(e) => actions.setGroupStream(group.id, e.target.value)} value={group.stream_id}>
|
||||
{
|
||||
streamsArray.map((stream) => (
|
||||
<option value={stream.id} key={stream.id}>
|
||||
{stream.id}
|
||||
{' '}
|
||||
(
|
||||
{stream.status}
|
||||
)
|
||||
</option>
|
||||
))
|
||||
}
|
||||
</select>
|
||||
<SelectField
|
||||
onChange={(value) => actions.setGroupStream(group.id, value)}
|
||||
value={group.stream_id}
|
||||
options={streamsArray.map((stream) => (
|
||||
{ value: stream.id, label: `${stream.id} (${stream.status})` }
|
||||
))}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field">
|
||||
@ -86,12 +81,13 @@ const SnapcastGroups = (props) => {
|
||||
<div className="input">
|
||||
<MuteControl
|
||||
className="snapcast__group__mute-control snapcast__mute-control"
|
||||
mute={group.muted}
|
||||
mute={group.mute}
|
||||
onMuteChange={(mute) => actions.setGroupMute(group.id, mute)}
|
||||
/>
|
||||
<VolumeControl
|
||||
className="snapcast__group__volume-control snapcast__volume-control"
|
||||
volume={group_volume}
|
||||
mute={group.mute}
|
||||
onVolumeChange={(percent, previousPercent) => actions.setGroupVolume(group.id, percent, previousPercent)}
|
||||
/>
|
||||
</div>
|
||||
@ -156,8 +152,7 @@ const SnapcastGroups = (props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="snapcast__groups">
|
||||
<a name="services-snapcast-groups" />
|
||||
<div className="snapcast__groups" id="services-snapcast-groups">
|
||||
<div className="snapcast__groups__menu menu">
|
||||
<div className="menu__inner">
|
||||
{groupsArray.map((group) => renderMenuItem(group))}
|
||||
|
||||
@ -879,10 +879,6 @@ export const formatGroup = function (data) {
|
||||
}
|
||||
}
|
||||
|
||||
if (group.name === undefined || group.name === '') {
|
||||
group.name = `Group ${data.id.substring(0, 3)}`;
|
||||
}
|
||||
|
||||
if (group.mute === undefined && data.mute !== undefined) {
|
||||
group.mute = data.mute;
|
||||
}
|
||||
|
||||
@ -285,11 +285,10 @@ const SnapcastMiddleware = (function () {
|
||||
|
||||
case 'SNAPCAST_GROUPS_LOADED':
|
||||
var groups_index = { ...snapcast.groups };
|
||||
var groups_loaded = [];
|
||||
var clients_loaded = [];
|
||||
|
||||
for (const raw_group of action.groups) {
|
||||
var group = helpers.formatGroup(raw_group);
|
||||
const groups_loaded = action.groups.map(raw_group => {
|
||||
let group = helpers.formatGroup(raw_group);
|
||||
|
||||
if (groups_index[group.id]) {
|
||||
group = { ...groups_index[group.id], ...group };
|
||||
@ -300,8 +299,13 @@ const SnapcastMiddleware = (function () {
|
||||
clients_loaded = [...clients_loaded, ...raw_group.clients];
|
||||
}
|
||||
|
||||
groups_loaded.push(group);
|
||||
}
|
||||
// Create a name (display only) based on it's ID
|
||||
if (group.name === undefined || group.name === '') {
|
||||
group.name = `Group ${group.id.substring(0, 3)}`;
|
||||
}
|
||||
|
||||
return group;
|
||||
});
|
||||
|
||||
action.groups = groups_loaded;
|
||||
|
||||
@ -462,7 +466,7 @@ const SnapcastMiddleware = (function () {
|
||||
request(store, 'Group.SetClients', params)
|
||||
.then(
|
||||
response => {
|
||||
store.dispatch(snapcastActions.serverLoaded(response.server));
|
||||
store.dispatch(snapcastActions.groupsLoaded(response.server.groups, true));
|
||||
},
|
||||
error => {
|
||||
store.dispatch(coreActions.handleException(
|
||||
@ -557,7 +561,7 @@ const SnapcastMiddleware = (function () {
|
||||
store.dispatch(snapcastActions.groupLoaded(
|
||||
{
|
||||
id: action.id,
|
||||
muted: response.mute,
|
||||
mute: response.mute,
|
||||
},
|
||||
));
|
||||
},
|
||||
|
||||
@ -73,27 +73,24 @@ class LibraryBrowseDirectory extends React.Component {
|
||||
const uri_elements = uri.split('/');
|
||||
|
||||
return (
|
||||
<h4>
|
||||
<h4 className="breadcrumbs">
|
||||
{uri_elements.map((uri_element, index) => {
|
||||
// Reconstruct a URL to this element
|
||||
let uri = 'file://';
|
||||
for (let i = 0; i <= index; i++) {
|
||||
uri += `/${uri_elements[i]}`;
|
||||
}
|
||||
let uri = 'file://';
|
||||
for (let i = 0; i <= index; i++) {
|
||||
uri += `/${uri_elements[i]}`;
|
||||
}
|
||||
|
||||
return (
|
||||
return (
|
||||
<span key={uri}>
|
||||
{index > 0 && (
|
||||
<span>
|
||||
<Icon type="fontawesome" name="angle-right" />
|
||||
{' '}
|
||||
</span>
|
||||
<Icon type="fontawesome" name="angle-right" />
|
||||
)}
|
||||
<URILink type="browse" uri={uri}>
|
||||
{decodeURI(uri_element)}
|
||||
</URILink>
|
||||
</span>
|
||||
);
|
||||
);
|
||||
})}
|
||||
</h4>
|
||||
);
|
||||
|
||||
@ -38,6 +38,8 @@
|
||||
@import 'components/related-artists';
|
||||
@import 'components/error-message';
|
||||
@import 'components/sortable';
|
||||
@import 'components/mute-control';
|
||||
@import 'components/select-field';
|
||||
|
||||
@import 'views/artist';
|
||||
@import 'views/user';
|
||||
|
||||
@ -1 +1,4 @@
|
||||
|
||||
.mute-control {
|
||||
cursor: pointer;
|
||||
}
|
||||
12
src/scss/components/_select-field.scss
Normal file
12
src/scss/components/_select-field.scss
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
.select-field {
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
&__icon {
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
right: 14px;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
@ -292,6 +292,13 @@ h4 {
|
||||
margin-bottom: -1px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
&.breadcrumbs {
|
||||
.icon {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
|
||||
Reference in New Issue
Block a user