hovering now-playing cover thumb shows full-res art

This commit is contained in:
2026-02-23 15:53:30 -05:00
parent 967816ccd2
commit a6b476399e
@@ -1,6 +1,7 @@
import { LitElement, html, css } from 'lit'; import { LitElement, html, css, nothing } from 'lit';
import { customElement, state } from 'lit/decorators.js'; import { customElement, state } from 'lit/decorators.js';
import '@awesome.me/webawesome/dist/components/icon/icon.js'; import '@awesome.me/webawesome/dist/components/icon/icon.js';
import '@awesome.me/webawesome/dist/components/popup/popup.js';
import { PlayerController } from '@store/controllers/player-controller'; import { PlayerController } from '@store/controllers/player-controller';
const MIN_WIDTH = 120; const MIN_WIDTH = 120;
@@ -14,6 +15,9 @@ export class NowPlaying extends LitElement {
@state() @state()
private isDragging = false; private isDragging = false;
@state()
private showCoverPreview = false;
static override styles = css` static override styles = css`
:host { :host {
display: block; display: block;
@@ -59,6 +63,25 @@ export class NowPlaying extends LitElement {
font-size: 24px; font-size: 24px;
} }
.cover-art-wrapper {
position: relative;
}
.cover-preview-panel {
width: 500px;
height: 500px;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
pointer-events: none;
}
.cover-preview-panel img {
width: 100%;
height: 100%;
object-fit: cover;
}
.track-info { .track-info {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -132,23 +155,54 @@ export class NowPlaying extends LitElement {
return html` return html`
<div class="now-playing"> <div class="now-playing">
<div class="cover-art"> <div class="cover-art-wrapper">
${track.coverArt <div
? html`<img class="cover-art"
src="${track.coverArtSmall || track.coverArt}" @mouseenter=${this.handleCoverMouseEnter}
alt="Album cover" @mouseleave=${this.handleCoverMouseLeave}
@error=${(e: Event) => { >
const img = e.target as HTMLImageElement; ${track.coverArt
if (track.coverArt && img.src !== track.coverArt) { ? html`<img
img.src = track.coverArt; src="${track.coverArtSmall || track.coverArt}"
} alt="Album cover"
}} @error=${(e: Event) => {
/>` const img = e.target as HTMLImageElement;
: html`<div class="cover-placeholder"><wa-icon name="music"></wa-icon></div>`} if (
track.coverArt &&
img.src !== track.coverArt
) {
img.src = track.coverArt;
}
}}
/>`
: html`<div class="cover-placeholder">
<wa-icon name="music"></wa-icon>
</div>`}
</div>
<wa-popup
id="cover-preview"
placement="top-start"
flip
shift
.active=${this.showCoverPreview}
>
${this.showCoverPreview && track.coverArt
? html`
<div class="cover-preview-panel">
<img
src="${track.coverArt}"
alt="Album cover full size"
/>
</div>
`
: nothing}
</wa-popup>
</div> </div>
<div class="track-info"> <div class="track-info">
<span class="track-title">${track.title}</span> <span class="track-title">${track.title}</span>
<span class="track-artist">${track.artist || 'Unknown Artist'}</span> <span class="track-artist">
${track.artist || 'Unknown Artist'}
</span>
</div> </div>
</div> </div>
<div <div
@@ -158,6 +212,31 @@ export class NowPlaying extends LitElement {
`; `;
} }
private handleCoverMouseEnter = () => {
const track = this.player.currentTrack;
if (!track?.coverArt) return;
this.showCoverPreview = true;
this.updateComplete.then(() => {
const popup = this.shadowRoot?.querySelector(
'#cover-preview',
);
const anchor = this.shadowRoot?.querySelector(
'.cover-art',
);
if (popup && anchor) {
(popup as any).anchor = anchor;
}
});
};
private handleCoverMouseLeave = () => {
this.showCoverPreview = false;
};
private handleMouseDown = (e: MouseEvent) => { private handleMouseDown = (e: MouseEvent) => {
e.preventDefault(); e.preventDefault();
this.isDragging = true; this.isDragging = true;