@@ -61,6 +61,7 @@ els('.room').forEach((node) => {
|
||||
toggle: el('[data-role="group"]', node),
|
||||
toggleLabel: el('[data-role="group-label"]', node),
|
||||
play: el('[data-role="play"]', node),
|
||||
next: el('[data-role="next"]', node),
|
||||
steps: els('.step', node),
|
||||
volume: null,
|
||||
playState: null,
|
||||
@@ -80,6 +81,7 @@ els('.room').forEach((node) => {
|
||||
|
||||
room.toggle.addEventListener('click', () => setGrouped(key, !room.grouped));
|
||||
room.play.addEventListener('click', () => togglePlay(key));
|
||||
room.next.addEventListener('click', () => skipTrack(key));
|
||||
});
|
||||
|
||||
function paintRoom(room) {
|
||||
@@ -93,6 +95,12 @@ function paintRoom(room) {
|
||||
room.play.disabled = !room.available || room.playState === null;
|
||||
room.play.setAttribute(
|
||||
'aria-label', `${room.node.querySelector('h2').textContent}: ${playing ? 'pause' : 'play'}`);
|
||||
// Grouped, transport belongs to the AVR's card, not this one -- pressing
|
||||
// either here would still work (it shares the group's transport) but
|
||||
// only invites confusion about which card is actually in charge of it.
|
||||
room.play.hidden = room.grouped;
|
||||
room.next.hidden = !playing || room.grouped;
|
||||
room.next.disabled = !room.available;
|
||||
|
||||
room.toggle.disabled = !room.available;
|
||||
room.toggle.classList.toggle('busy', room.busy);
|
||||
@@ -225,6 +233,18 @@ async function togglePlay(key) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Fire-and-forget: the queue's next track has no local state to reconcile,
|
||||
so there is nothing to optimistically flip the way play/pause does. */
|
||||
async function skipTrack(key) {
|
||||
const room = rooms[key];
|
||||
if (!room.available) return;
|
||||
try {
|
||||
await api('/api/skip', { target: key, direction: 'next' });
|
||||
} catch (error) {
|
||||
toast(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
function applyJoined(joined) {
|
||||
Object.values(rooms).forEach((room) => {
|
||||
room.grouped = joined.includes(room.key);
|
||||
|
||||
+3
-3
@@ -124,7 +124,7 @@ svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width:
|
||||
|
||||
.transport {
|
||||
flex: 0 0 auto;
|
||||
width: 66px; height: 52px;
|
||||
width: 66px; height: 62px;
|
||||
border-radius: 16px;
|
||||
background: var(--raised);
|
||||
display: grid; place-items: center;
|
||||
@@ -136,6 +136,7 @@ svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width:
|
||||
everything else in here uses. */
|
||||
.transport .icon-play { fill: currentColor; stroke: none; }
|
||||
.transport .icon-pause { stroke-width: 2.4; }
|
||||
.transport[data-role="next"] svg { fill: currentColor; stroke: none; }
|
||||
|
||||
/* Which icon shows is a class on the button, not `hidden` on the svg:
|
||||
`hidden` is an HTMLElement property and SVGElement does not inherit it,
|
||||
@@ -146,7 +147,7 @@ svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width:
|
||||
|
||||
/* --- join / leave the AVR -------------------------------------------- */
|
||||
.toggle {
|
||||
height: 52px; border-radius: 16px;
|
||||
height: 62px; border-radius: 16px;
|
||||
background: var(--raised);
|
||||
display: flex; align-items: center; justify-content: center; gap: 10px;
|
||||
font-size: 15px; font-weight: 550;
|
||||
@@ -191,7 +192,6 @@ svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width:
|
||||
background: none; border: 1px solid var(--edge); color: var(--muted);
|
||||
}
|
||||
.joined .toggle .dot { display: none; }
|
||||
.joined .transport { height: 40px; width: 58px; }
|
||||
.joined .toggle:active { background: var(--raised); color: var(--ink); }
|
||||
|
||||
/* --- misc ------------------------------------------------------------- */
|
||||
|
||||
Reference in New Issue
Block a user