Add cards
This commit is contained in:
parent
79f3ce458a
commit
74badced08
|
@ -31,5 +31,7 @@ module.exports = createActionCreators({
|
||||||
SET_SOURCE_CHANNEL_VOLUME: (index, channelIndex, volume) => ({ index, channelIndex, volume }),
|
SET_SOURCE_CHANNEL_VOLUME: (index, channelIndex, volume) => ({ index, channelIndex, volume }),
|
||||||
SET_SINK_INPUT_CHANNEL_VOLUME: (index, channelIndex, volume) => ({ index, channelIndex, volume }),
|
SET_SINK_INPUT_CHANNEL_VOLUME: (index, channelIndex, volume) => ({ index, channelIndex, volume }),
|
||||||
SET_SOURCE_OUTPUT_CHANNEL_VOLUME: (index, channelIndex, volume) => ({ index, channelIndex, volume }),
|
SET_SOURCE_OUTPUT_CHANNEL_VOLUME: (index, channelIndex, volume) => ({ index, channelIndex, volume }),
|
||||||
|
|
||||||
|
SET_CARD_PROFILE: (index, profileName) => ({ index, profileName }),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
const r = require('r-dom');
|
const r = require('r-dom');
|
||||||
|
|
||||||
const Button = props => r.button({
|
const Button = props => r.button({
|
||||||
|
className: 'button',
|
||||||
...props,
|
...props,
|
||||||
}, props.children);
|
}, props.children);
|
||||||
|
|
||||||
|
|
83
components/cards/index.js
Normal file
83
components/cards/index.js
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
|
||||||
|
const {
|
||||||
|
values,
|
||||||
|
map,
|
||||||
|
path,
|
||||||
|
} = require('ramda');
|
||||||
|
|
||||||
|
const r = require('r-dom');
|
||||||
|
|
||||||
|
const { connect } = require('react-redux');
|
||||||
|
const { bindActionCreators } = require('redux');
|
||||||
|
|
||||||
|
const { withStateHandlers } = require('recompose');
|
||||||
|
|
||||||
|
const { pulse: pulseActions } = require('../../actions');
|
||||||
|
|
||||||
|
const Button = require('../button');
|
||||||
|
const Label = require('../label');
|
||||||
|
const Select = require('../select');
|
||||||
|
|
||||||
|
const Preferences = withStateHandlers(
|
||||||
|
{
|
||||||
|
open: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toggle: ({ open }) => () => ({ open: !open }),
|
||||||
|
},
|
||||||
|
)(({ open, toggle, ...props }) => r.div({
|
||||||
|
classSet: {
|
||||||
|
panel: true,
|
||||||
|
cards: true,
|
||||||
|
open,
|
||||||
|
},
|
||||||
|
}, open ? [
|
||||||
|
r.div([
|
||||||
|
r(Button, {
|
||||||
|
style: { width: '100%' },
|
||||||
|
onClick: toggle,
|
||||||
|
}, 'Close'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
r.hr(),
|
||||||
|
|
||||||
|
...map(card => r(Label, {
|
||||||
|
title: card.name,
|
||||||
|
}, [
|
||||||
|
r(Label, [
|
||||||
|
path([ 'properties', 'device', 'description' ], card),
|
||||||
|
]),
|
||||||
|
|
||||||
|
r(Select, {
|
||||||
|
options: card.profiles,
|
||||||
|
optionValue: p => p.name,
|
||||||
|
optionText: p => p.description,
|
||||||
|
value: card.activeProfileName,
|
||||||
|
onChange: e => {
|
||||||
|
props.actions.setCardProfile(card.index, e.target.value);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]), values(props.cards)),
|
||||||
|
|
||||||
|
props.preferences.showDebugInfo && r.pre({
|
||||||
|
style: {
|
||||||
|
fontSize: '0.75em',
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
JSON.stringify(props, null, 2),
|
||||||
|
]),
|
||||||
|
] : [
|
||||||
|
r(Button, {
|
||||||
|
onClick: toggle,
|
||||||
|
}, 'Cards'),
|
||||||
|
]));
|
||||||
|
|
||||||
|
module.exports = connect(
|
||||||
|
state => ({
|
||||||
|
cards: state.pulse.infos.cards,
|
||||||
|
preferences: state.preferences,
|
||||||
|
}),
|
||||||
|
dispatch => ({
|
||||||
|
actions: bindActionCreators(pulseActions, dispatch),
|
||||||
|
}),
|
||||||
|
)(Preferences);
|
|
@ -3,4 +3,5 @@ const r = require('r-dom');
|
||||||
|
|
||||||
module.exports = props => r.label({
|
module.exports = props => r.label({
|
||||||
className: 'label',
|
className: 'label',
|
||||||
|
...props,
|
||||||
}, props.children);
|
}, props.children);
|
||||||
|
|
|
@ -26,6 +26,7 @@ const Preferences = withStateHandlers(
|
||||||
},
|
},
|
||||||
)(({ open, toggle, ...props }) => r.div({
|
)(({ open, toggle, ...props }) => r.div({
|
||||||
classSet: {
|
classSet: {
|
||||||
|
panel: true,
|
||||||
preferences: true,
|
preferences: true,
|
||||||
open,
|
open,
|
||||||
},
|
},
|
||||||
|
|
7
components/select/index.js
Normal file
7
components/select/index.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
const r = require('r-dom');
|
||||||
|
|
||||||
|
module.exports = ({ options, optionValue, optionText, ...props }) => r.select({
|
||||||
|
className: 'select',
|
||||||
|
...props,
|
||||||
|
}, options.map(o => r.option({ value: optionValue(o) }, optionText(o))));
|
42
index.css
42
index.css
|
@ -9,7 +9,7 @@ div {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
.button {
|
||||||
background: var(--themeBgColor);
|
background: var(--themeBgColor);
|
||||||
color: var(--themeTextColor);
|
color: var(--themeTextColor);
|
||||||
border: 1px solid var(--borders);
|
border: 1px solid var(--borders);
|
||||||
|
@ -18,16 +18,16 @@ button {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
button:hover {
|
.button:hover {
|
||||||
border-color: var(--themeSelectedBgColor);
|
border-color: var(--themeSelectedBgColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
button:focus {
|
.button:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: var(--themeSelectedBgColor);
|
border-color: var(--themeSelectedBgColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
button:active {
|
.button:active {
|
||||||
background: var(--themeSelectedBgColor);
|
background: var(--themeSelectedBgColor);
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 1px;
|
top: 1px;
|
||||||
|
@ -62,6 +62,21 @@ button:active {
|
||||||
width: 64px;
|
width: 64px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.select {
|
||||||
|
background: var(--themeUnfocusedBgColor);
|
||||||
|
color: var(--themeUnfocusedFgColor);
|
||||||
|
border: 1px solid var(--borders);
|
||||||
|
padding: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.select:hover {
|
||||||
|
border-color: var(--themeSelectedBgColor);
|
||||||
|
}
|
||||||
|
.select:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--themeSelectedBgColor);
|
||||||
|
}
|
||||||
|
|
||||||
.view-wrapper .graph {
|
.view-wrapper .graph {
|
||||||
background: var(--themeBaseColor);
|
background: var(--themeBaseColor);
|
||||||
}
|
}
|
||||||
|
@ -138,28 +153,35 @@ button:active {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.preferences {
|
.panel {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.preferences:not(.open) {
|
.cards {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preferences {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel:not(.open) {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.preferences:not(.open) > * {
|
.panel:not(.open) > * {
|
||||||
pointer-events: initial;
|
pointer-events: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
.preferences.open {
|
.panel.open {
|
||||||
background: var(--themeBgColor);
|
background: var(--themeBgColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
.preferences > hr {
|
.panel > hr {
|
||||||
border: none;
|
border: none;
|
||||||
border-top: 1px solid var(--borders);
|
border-top: 1px solid var(--borders);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@futpib/paclient": "^0.0.5",
|
"@futpib/paclient": "^0.0.7",
|
||||||
"bluebird": "^3.5.3",
|
"bluebird": "^3.5.3",
|
||||||
"camelcase": "^5.0.0",
|
"camelcase": "^5.0.0",
|
||||||
"electron-store": "^2.0.0",
|
"electron-store": "^2.0.0",
|
||||||
|
|
|
@ -11,6 +11,7 @@ const { Provider } = require('react-redux');
|
||||||
const createStore = require('./store');
|
const createStore = require('./store');
|
||||||
|
|
||||||
const Graph = require('./components/graph');
|
const Graph = require('./components/graph');
|
||||||
|
const Cards = require('./components/cards');
|
||||||
const Preferences = require('./components/preferences');
|
const Preferences = require('./components/preferences');
|
||||||
|
|
||||||
const theme = require('./utils/theme');
|
const theme = require('./utils/theme');
|
||||||
|
@ -19,6 +20,7 @@ const Root = () => r(Provider, {
|
||||||
store: createStore(),
|
store: createStore(),
|
||||||
}, r(React.Fragment, [
|
}, r(React.Fragment, [
|
||||||
r(Graph),
|
r(Graph),
|
||||||
|
r(Cards),
|
||||||
r(Preferences),
|
r(Preferences),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,19 @@ function setSourceOutputChannelVolume(pa, store, index, channelIndex, volume, cb
|
||||||
module.exports = store => {
|
module.exports = store => {
|
||||||
const pa = new PAClient();
|
const pa = new PAClient();
|
||||||
|
|
||||||
const getInfo = (type, index) => pa[getFnFromType(type)](index, (err, info) => {
|
const getInfo = (type, index) => {
|
||||||
|
let method;
|
||||||
|
try {
|
||||||
|
method = getFnFromType(type);
|
||||||
|
} catch (error) {
|
||||||
|
if (error.message.startsWith('Unexpected type:')) {
|
||||||
|
console.warn(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
pa[method](index, (err, info) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err.message === 'No such entity') {
|
if (err.message === 'No such entity') {
|
||||||
console.warn(err.message, type, index);
|
console.warn(err.message, type, index);
|
||||||
|
@ -62,6 +74,7 @@ module.exports = store => {
|
||||||
info.type = info.type || type;
|
info.type = info.type || type;
|
||||||
store.dispatch(pulseActions.info(info));
|
store.dispatch(pulseActions.info(info));
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
pa
|
pa
|
||||||
.on('ready', () => {
|
.on('ready', () => {
|
||||||
|
@ -178,6 +191,10 @@ module.exports = store => {
|
||||||
return setSourceOutputChannelVolume(pa, store, index, channelIndex, volume, rethrow);
|
return setSourceOutputChannelVolume(pa, store, index, channelIndex, volume, rethrow);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
[pulseActions.setCardProfile]: (state, { payload: { index, profileName } }) => {
|
||||||
|
pa.setCardProfile(index, profileName, rethrow);
|
||||||
|
return state;
|
||||||
|
},
|
||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
return next => action => {
|
return next => action => {
|
||||||
|
|
|
@ -84,10 +84,10 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
arrify "^1.0.1"
|
arrify "^1.0.1"
|
||||||
|
|
||||||
"@futpib/paclient@^0.0.5":
|
"@futpib/paclient@^0.0.7":
|
||||||
version "0.0.5"
|
version "0.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/@futpib/paclient/-/paclient-0.0.5.tgz#0de89ee7175e3de994bc298ddb1e461aa3007543"
|
resolved "https://registry.yarnpkg.com/@futpib/paclient/-/paclient-0.0.7.tgz#d8957135ba81888f5e92812d8e9e4e8e1ebf935f"
|
||||||
integrity sha512-49jeRSEOXto3MntDj2Dzm4t7U9M0X41seqF+T/xwFRYk/pBUKdiXHuofNFJvn4rwM7P4BVjxU6fRpCOEAxH/VA==
|
integrity sha512-fjpJaS3LHuo+51/7g3dqpZBGO2wZtnLAWYKVk5CIBsfqn3345xJaEe0HfLpBxPAdpAHRTcTz5aWXlhOWsBClHA==
|
||||||
|
|
||||||
"@ladjs/time-require@^0.1.4":
|
"@ladjs/time-require@^0.1.4":
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user