mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-13 20:36:35 +00:00
Redesign media player card (thanks @DesignFirst)
This commit is contained in:
parent
ed6d3cfa1d
commit
4ab308a9d2
@ -29,6 +29,7 @@
|
|||||||
"babel-loader": "^6.2",
|
"babel-loader": "^6.2",
|
||||||
"babel-preset-es2015": "^6.6.0",
|
"babel-preset-es2015": "^6.6.0",
|
||||||
"bower": "^1.7.9",
|
"bower": "^1.7.9",
|
||||||
|
"classnames": "^2.2.3",
|
||||||
"eslint": "^2.7.0",
|
"eslint": "^2.7.0",
|
||||||
"eslint-config-airbnb": "^6.2.0",
|
"eslint-config-airbnb": "^6.2.0",
|
||||||
"html-minifier": "^1.4.0",
|
"html-minifier": "^1.4.0",
|
||||||
|
@ -10,57 +10,83 @@
|
|||||||
font-size: 0px;
|
font-size: 0px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
|
|
||||||
transition: height .5s;
|
|
||||||
|
|
||||||
background-size: cover;
|
|
||||||
background-position: center center;
|
|
||||||
background-color: var(--paper-grey-500);
|
|
||||||
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.options {
|
.banner {
|
||||||
float: right;
|
position: relative;
|
||||||
margin-right: -8px;
|
|
||||||
margin-top: -8px;
|
background-position: center center;
|
||||||
|
background-image: url(/static/images/card_media_player_bg.png);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.caption {
|
.banner:before {
|
||||||
|
display: block;
|
||||||
|
content: "";
|
||||||
|
width: 100%;
|
||||||
|
/* removed .25% from 16:9 ratio to fix YT black bars */
|
||||||
|
padding-top: 56%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner > .cover {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
|
||||||
|
border-top-left-radius: 2px;
|
||||||
|
border-top-right-radius: 2px;
|
||||||
|
|
||||||
|
background-position: center center;
|
||||||
|
background-size: cover;
|
||||||
|
transition: opacity .8s;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner.is-off > .cover {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner > .caption {
|
||||||
@apply(--paper-font-caption);
|
@apply(--paper-font-caption);
|
||||||
border-bottom-left-radius: 2px;
|
|
||||||
border-bottom-right-radius: 2px;
|
|
||||||
|
|
||||||
background: linear-gradient(to bottom,
|
position: absolute;
|
||||||
rgba(0,0,0,0.5) 0%,
|
left: 0;
|
||||||
rgba(0,0,0,0) 100%);
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
|
||||||
padding: 8px;
|
background-color: rgba(0, 0, 0, var(--dark-secondary-opacity));
|
||||||
|
|
||||||
|
padding: 16px;
|
||||||
|
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: white;
|
color: white;
|
||||||
|
|
||||||
|
transition: background-color .5s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.caption .title {
|
.banner.is-off > .caption {
|
||||||
|
background-color: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.banner > .caption .title {
|
||||||
@apply(--paper-font-common-nowrap);
|
@apply(--paper-font-common-nowrap);
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
margin-bottom: 4px;
|
margin: 8px 0 4px;
|
||||||
}
|
|
||||||
|
|
||||||
.controls-container {
|
|
||||||
position: absolute;
|
|
||||||
left: 8px;
|
|
||||||
right: 8px;
|
|
||||||
top: 91px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.controls {
|
.controls {
|
||||||
@apply(--paper-font-body1);
|
@apply(--paper-font-body1);
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
border-radius: 2px;
|
border-bottom-left-radius: 2px;
|
||||||
|
border-bottom-right-radius: 2px;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.controls paper-icon-button {
|
.controls paper-icon-button {
|
||||||
@ -68,6 +94,10 @@
|
|||||||
height: 44px;
|
height: 44px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
paper-icon-button {
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
paper-icon-button.primary {
|
paper-icon-button.primary {
|
||||||
width: 56px !important;
|
width: 56px !important;
|
||||||
height: 56px !important;
|
height: 56px !important;
|
||||||
@ -75,6 +105,11 @@
|
|||||||
color: white;
|
color: white;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
transition: background-color .5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
paper-icon-button.primary[disabled] {
|
||||||
|
background-color: rgba(0, 0, 0, var(--dark-disabled-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
[invisible] {
|
[invisible] {
|
||||||
@ -82,63 +117,50 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<template>
|
<template>
|
||||||
<img src='[[stateObj.attributes.entity_picture]]' hidden
|
<div class$='[[computeBannerClasses(playerObj)]]'>
|
||||||
on-load='imageLoadSuccess' on-error='imageLoadFail'>
|
<div class='cover' id='cover'></div>
|
||||||
|
|
||||||
<div class='caption'>
|
<div class='caption'>
|
||||||
<div class='options'>
|
[[stateObj.entityDisplay]]
|
||||||
<paper-icon-button
|
<div class='title'>[[playerObj.primaryText]]</div>
|
||||||
class='power-on'
|
[[playerObj.secondaryText]]<br />
|
||||||
icon='mdi:power'
|
|
||||||
on-tap='handlePowerOn'
|
|
||||||
hidden$='[[computeHidePowerOnButton(playerObj)]]'
|
|
||||||
></paper-icon-button>
|
|
||||||
<paper-icon-button
|
|
||||||
icon='mdi:open-in-app'
|
|
||||||
on-tap='handleOpenMoreInfo'
|
|
||||||
></paper-icon-button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class='title'>[[playerObj.primaryText]]</div>
|
|
||||||
[[playerObj.secondaryText]]<br />
|
|
||||||
@[[stateObj.entityDisplay]]
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class='controls-container'>
|
<div class='controls layout horizontal justified'>
|
||||||
<paper-material elevation="1">
|
<paper-icon-button
|
||||||
<div class='controls layout horizontal justified'>
|
icon='mdi:power'
|
||||||
<paper-icon-button
|
on-tap='handleTogglePower'
|
||||||
icon='[[computeVolumeMuteIcon(playerObj)]]'
|
invisible$='[[!playerObj.supportsTurnOff]]'
|
||||||
on-tap='handleVolumeMute'
|
class='self-center secondary'
|
||||||
invisible$='[[!playerObj.supportsVolumeMute]]'
|
></paper-icon-button>
|
||||||
class='self-center'
|
|
||||||
></paper-icon-button>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<paper-icon-button
|
<paper-icon-button
|
||||||
icon='mdi:skip-previous'
|
icon='mdi:skip-previous'
|
||||||
invisible$='[[!playerObj.supportsPreviousTrack]]'
|
invisible$='[[!playerObj.supportsPreviousTrack]]'
|
||||||
on-tap='handlePrevious'
|
on-tap='handlePrevious'
|
||||||
></paper-icon-button>
|
></paper-icon-button>
|
||||||
<paper-icon-button
|
<paper-icon-button
|
||||||
class='primary'
|
class='primary'
|
||||||
icon='[[computePlaybackControlIcon(playerObj)]]'
|
icon='[[computePlaybackControlIcon(playerObj)]]'
|
||||||
on-tap='handlePlaybackControl'
|
invisible='[[!computePlaybackControlIcon(playerObj)]]'
|
||||||
></paper-icon-button>
|
disabled='[[playerObj.isOff]]'
|
||||||
<paper-icon-button
|
on-tap='handlePlaybackControl'
|
||||||
icon='mdi:skip-next'
|
></paper-icon-button>
|
||||||
invisible$='[[!playerObj.supportsNextTrack]]'
|
<paper-icon-button
|
||||||
on-tap='handleNext'
|
icon='mdi:skip-next'
|
||||||
></paper-icon-button>
|
invisible$='[[!playerObj.supportsNextTrack]]'
|
||||||
</div>
|
on-tap='handleNext'
|
||||||
|
></paper-icon-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<paper-icon-button
|
||||||
|
icon='mdi:dots-vertical'
|
||||||
|
on-tap='handleOpenMoreInfo'
|
||||||
|
class='self-center secondary'
|
||||||
|
></paper-icon-button>
|
||||||
|
|
||||||
<paper-icon-button
|
|
||||||
icon='mdi:power'
|
|
||||||
on-tap='handlePowerOff'
|
|
||||||
invisible$='[[!playerObj.supportsTurnOff]]'
|
|
||||||
class='self-center'
|
|
||||||
></paper-icon-button>
|
|
||||||
</div>
|
|
||||||
</paper-material>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</dom-module>
|
</dom-module>
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
import Polymer from '../polymer';
|
import Polymer from '../polymer';
|
||||||
import hass from '../util/home-assistant-js-instance';
|
import hass from '../util/home-assistant-js-instance';
|
||||||
|
|
||||||
@ -17,11 +19,6 @@ export default new Polymer({
|
|||||||
observer: 'playerObjChanged',
|
observer: 'playerObjChanged',
|
||||||
},
|
},
|
||||||
|
|
||||||
imageLoaded: {
|
|
||||||
type: Boolean,
|
|
||||||
value: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
playbackControlIcon: {
|
playbackControlIcon: {
|
||||||
type: String,
|
type: String,
|
||||||
computed: 'computePlaybackControlIcon(playerObj)',
|
computed: 'computePlaybackControlIcon(playerObj)',
|
||||||
@ -38,17 +35,17 @@ export default new Polymer({
|
|||||||
},
|
},
|
||||||
|
|
||||||
playerObjChanged(playerObj) {
|
playerObjChanged(playerObj) {
|
||||||
this.style.height = this.computeShowControls(playerObj) ? '175px' : '78px';
|
if (!playerObj.isOff && !playerObj.isIdle) {
|
||||||
this.style.backgroundImage = playerObj.stateObj.attributes.entity_picture ?
|
this.$.cover.style.backgroundImage = playerObj.stateObj.attributes.entity_picture ?
|
||||||
`url(${playerObj.stateObj.attributes.entity_picture})` : '';
|
`url(${playerObj.stateObj.attributes.entity_picture})` : '';
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
imageLoadSuccess() {
|
computeBannerClasses(playerObj) {
|
||||||
this.imageLoaded = true;
|
return classnames({
|
||||||
},
|
banner: true,
|
||||||
|
'is-off': playerObj.isOff || playerObj.isIdle,
|
||||||
imageLoadFail() {
|
});
|
||||||
this.imageLoaded = false;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
computeHidePowerOnButton(playerObj) {
|
computeHidePowerOnButton(playerObj) {
|
||||||
@ -62,7 +59,7 @@ export default new Polymer({
|
|||||||
computePlaybackControlIcon(playerObj) {
|
computePlaybackControlIcon(playerObj) {
|
||||||
if (playerObj.isPlaying) {
|
if (playerObj.isPlaying) {
|
||||||
return playerObj.supportsPause ? 'mdi:pause' : 'mdi:stop';
|
return playerObj.supportsPause ? 'mdi:pause' : 'mdi:stop';
|
||||||
} else if (playerObj.isPaused) {
|
} else if (playerObj.isPaused || playerObj.isOff) {
|
||||||
return 'mdi:play';
|
return 'mdi:play';
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
@ -72,10 +69,6 @@ export default new Polymer({
|
|||||||
return !playerObj.isOff;
|
return !playerObj.isOff;
|
||||||
},
|
},
|
||||||
|
|
||||||
computeVolumeMuteIcon(playerObj) {
|
|
||||||
return playerObj.isMuted ? 'mdi:volume-off' : 'mdi:volume-high';
|
|
||||||
},
|
|
||||||
|
|
||||||
handleNext(ev) {
|
handleNext(ev) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
this.playerObj.nextTrack();
|
this.playerObj.nextTrack();
|
||||||
@ -96,19 +89,8 @@ export default new Polymer({
|
|||||||
this.playerObj.previousTrack();
|
this.playerObj.previousTrack();
|
||||||
},
|
},
|
||||||
|
|
||||||
handlePowerOff(ev) {
|
handleTogglePower(ev) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
this.playerObj.turnOff();
|
this.playerObj.togglePower();
|
||||||
},
|
},
|
||||||
|
|
||||||
handlePowerOn(ev) {
|
|
||||||
ev.stopPropagation();
|
|
||||||
this.playerObj.turnOn();
|
|
||||||
},
|
|
||||||
|
|
||||||
handleVolumeMute(ev) {
|
|
||||||
ev.stopPropagation();
|
|
||||||
this.playerObj.volumeMute(!this.playerObj.isMuted);
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user