Added 'Show While Paused' option to all themes

This commit is contained in:
nutty
2026-08-27 14:23:21 +10:00
parent e355275cc2
commit 41a66d8c63
23 changed files with 364 additions and 40 deletions
+1 -1
View File
@@ -443,7 +443,7 @@ async function UpdatePlayerState(data) {
const isPlaying = (targetSession.playback_info.PlaybackStatus === PlaybackStatus.PLAYING);
const currentPositionMs = isPlaying && timelineProps.EndTime > 0 ? timelineProps.Position + driftMs : timelineProps.Position;
SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette);
SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette, targetSession.playback_info.PlaybackStatus);
}
}
else {
+16 -16
View File
@@ -150,6 +150,14 @@
"showIf": "useCustomColors",
"group": "Appearance"
},
{
"id": "showWhilePaused",
"label": "Show While Paused",
"description": "If enabled, the widget will be visible even when the track is paused.",
"type": "checkbox",
"defaultValue": false,
"group": "General"
},
{
"id": "autoHide",
"label": "Auto-Hide on Track Change",
@@ -159,11 +167,14 @@
"group": "General"
},
{
"id": "showWhilePaused",
"label": "Show While Paused",
"description": "If enabled, the widget will be visible even when the track is paused.",
"type": "checkbox",
"defaultValue": false,
"id": "displayDuration",
"label": "Display Duration (seconds)",
"description": "How long the widget should remain visible.",
"type": "number",
"min": 1,
"max": 60,
"defaultValue": 5,
"showIf": "autoHide",
"group": "General"
},
{
@@ -224,17 +235,6 @@
"defaultValue": true,
"group": "General"
},
{
"id": "displayDuration",
"label": "Display Duration (seconds)",
"description": "How long the widget should remain visible.",
"type": "number",
"min": 1,
"max": 60,
"defaultValue": 5,
"showIf": "autoHide",
"group": "General"
},
{
"id": "showAnimation",
"label": "Show Animation",
+4 -4
View File
@@ -97,7 +97,7 @@ body {
@keyframes slide-in-from-left {
0% {
transform: translateX(-1em);
transform: translateX(-100%);
opacity: 0;
}
@@ -114,14 +114,14 @@ body {
}
100% {
transform: translateX(-1em);
transform: translateX(-100%);
opacity: 0;
}
}
@keyframes slide-in-from-right {
0% {
transform: translateX(1em);
transform: translateX(100%);
opacity: 0;
}
@@ -138,7 +138,7 @@ body {
}
100% {
transform: translateX(1em);
transform: translateX(100%);
opacity: 0;
}
}
+5
View File
@@ -3,6 +3,11 @@
<div id="album-art-container">
<div id="album-art-layer"></div>
<div id="album-art-transition-layer"></div>
<div id="pause-overlay">
<svg viewBox="0 0 24 24" style="fill: var(--accent-color, #ffffff);">
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>
</svg>
</div>
</div>
<div id="text-info-container">
+8 -3
View File
@@ -96,7 +96,12 @@ async function ChangeTrack(mediaProps, accentColorPalette) {
}, 250);
}
function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette) {
function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette, playbackStatus) {
// Set the pause overlay visibility based on playback status
if (playbackStatus === PlaybackStatus.PAUSED)
albumArtContainer.classList.add('is-paused');
else
albumArtContainer.classList.remove('is-paused');
// Set progressbar
// Ensure we don't divide by zero or exceed 100%
@@ -105,7 +110,7 @@ function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette) {
progressPercent = Math.min(100, Math.max(0, progressPercent));
progressBar.style.width = `${progressPercent}%`;
if (!useCustomColors)
progressBar.style.setProperty('--accent-color', accentColorPalette.LightVibrant);
document.body.style.setProperty('--accent-color', accentColorPalette.LightVibrant);
else
progressBar.style.setProperty('--accent-color', color1);
document.body.style.setProperty('--accent-color', color1);
}
+30
View File
@@ -21,6 +21,36 @@
display: var(--show-album-art);
}
#album-art-container.is-paused #album-art-layer,
#album-art-container.is-paused #album-art-transition-layer {
opacity: 0.7;
}
#pause-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease;
z-index: 10;
border-radius: inherit;
}
#pause-overlay svg {
height: 30%;
width: auto;
}
#album-art-container.is-paused #pause-overlay {
opacity: 1;
}
#album-art-layer,
#album-art-transition-layer {
position: absolute;
+5
View File
@@ -9,6 +9,11 @@
<div id="album-art-container">
<div id="album-art-layer"></div>
<div id="album-art-transition-layer"></div>
<div id="pause-overlay">
<svg viewBox="0 0 24 24" style="fill: var(--accent-color, #ffffff);">
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>
</svg>
</div>
</div>
<div id="track-label" class="text-label">&nbsp;</div>
+7 -1
View File
@@ -84,13 +84,19 @@ async function ChangeTrack(mediaProps, accentColorPalette) {
}, 250);
}
function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette) {
function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette, playbackStatus) {
// Update the label using your naming convention
currentTimeLabel.innerText =
ConvertMillisecondsToHoursMinutesSecondsSoItLooksBetterAndNotCringe(currentPositionMs);
durationLabel.innerText =
ConvertMillisecondsToHoursMinutesSecondsSoItLooksBetterAndNotCringe(timelineProps.EndTime);
// Set the pause overlay visibility based on playback status
if (playbackStatus === PlaybackStatus.PAUSED)
albumArtContainer.classList.add('is-paused');
else
albumArtContainer.classList.remove('is-paused');
// Set progressbar
// Ensure we don't divide by zero or exceed 100%
+30
View File
@@ -23,6 +23,36 @@
display: var(--show-album-art);
}
#album-art-container.is-paused #album-art-layer,
#album-art-container.is-paused #album-art-transition-layer {
opacity: 0.2;
}
#pause-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease;
z-index: 10;
border-radius: inherit;
}
#pause-overlay svg {
height: 30%;
width: auto;
}
#album-art-container.is-paused #pause-overlay {
opacity: 0.8;
}
#album-art-layer,
#album-art-transition-layer {
position: absolute;
+5
View File
@@ -3,6 +3,11 @@
<div id="album-art-container">
<div id="album-art-layer"></div>
<div id="album-art-transition-layer"></div>
<div id="pause-overlay">
<svg viewBox="0 0 24 24" style="fill: var(--accent-color, #ffffff);">
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>
</svg>
</div>
</div>
<div id="song-info-container">
+7 -1
View File
@@ -84,13 +84,19 @@ async function ChangeTrack(mediaProps, accentColorPalette) {
}, 250);
}
function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette) {
function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette, playbackStatus) {
// Update the label using your naming convention
currentTimeLabel.innerText =
ConvertMillisecondsToHoursMinutesSecondsSoItLooksBetterAndNotCringe(currentPositionMs);
durationLabel.innerText =
ConvertMillisecondsToHoursMinutesSecondsSoItLooksBetterAndNotCringe(timelineProps.EndTime);
// Set the pause overlay visibility based on playback status
if (playbackStatus === PlaybackStatus.PAUSED)
albumArtContainer.classList.add('is-paused');
else
albumArtContainer.classList.remove('is-paused');
// Set progressbar
// Ensure we don't divide by zero or exceed 100%
+31
View File
@@ -24,6 +24,37 @@
flex-shrink: 0;
}
#album-art-container.is-paused #album-art-layer,
#album-art-container.is-paused #album-art-transition-layer {
opacity: 0.7;
filter: grayscale(50%);
}
#pause-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease;
z-index: 10;
border-radius: inherit;
}
#pause-overlay svg {
height: 40%;
width: auto;
}
#album-art-container.is-paused #pause-overlay {
opacity: 1;
}
#album-art-layer,
#album-art-transition-layer {
position: absolute;
+1 -1
View File
@@ -94,7 +94,7 @@ async function ChangeTrack(mediaProps, accentColorPalette) {
}, 250);
}
function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette) {
function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette, playbackStatus) {
const durationMs = timelineProps.EndTime;
let progressPercent = durationMs > 0 ? (currentPositionMs / durationMs) * 100 : 0;
+7 -1
View File
@@ -97,7 +97,7 @@ async function ChangeTrack(mediaProps, accentColorPalette) {
}, 250);
}
function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette) {
function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette, playbackStatus) {
// Set progressbar
// Ensure we don't divide by zero or exceed 100%
const durationMs = timelineProps.EndTime;
@@ -122,6 +122,12 @@ function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette) {
// const transitionWidth = '1em';
// progressBar.style.maskImage = `linear-gradient(to right, black calc(${clipRight}% - ${transitionWidth}), transparent ${clipRight}%)`
// progressBarTrack.style.maskImage = `linear-gradient(to right, transparent calc(${clipRight}% - ${transitionWidth}), black ${clipRight}%)`;
// Set the pause overlay visibility based on playback status
if (playbackStatus === PlaybackStatus.PAUSED)
songInfoContainer.classList.add('is-paused');
else
songInfoContainer.classList.remove('is-paused');
}
// MARQUEE LOGIC
+4
View File
@@ -24,6 +24,10 @@
grid-template-areas: "stack";
}
#song-info-container.is-paused {
opacity: 0.8;
}
/* The content sits on top */
#progress-bar {
position: relative;
+5
View File
@@ -2,6 +2,11 @@
<div id="album-art-container">
<div id="album-art-layer"></div>
<div id="album-art-transition-layer"></div>
<div id="pause-overlay">
<svg viewBox="0 0 24 24" style="fill: var(--accent-color, #ffffff);">
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>
</svg>
</div>
</div>
<div id="song-info-container">
+9 -3
View File
@@ -78,13 +78,19 @@ async function ChangeTrack(mediaProps) {
}, 250);
}
function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette) {
function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette, playbackStatus) {
// Update the label using your naming convention
currentTimeLabel.innerText =
ConvertMillisecondsToHoursMinutesSecondsSoItLooksBetterAndNotCringe(currentPositionMs);
durationLabel.innerText =
ConvertMillisecondsToHoursMinutesSecondsSoItLooksBetterAndNotCringe(timelineProps.EndTime);
// Set the pause overlay visibility based on playback status
if (playbackStatus === PlaybackStatus.PAUSED)
albumArtContainer.classList.add('is-paused');
else
albumArtContainer.classList.remove('is-paused');
// Set progressbar
// Ensure we don't divide by zero or exceed 100%
@@ -95,12 +101,12 @@ function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette) {
if (!useCustomColors)
{
progressBarFill.style.setProperty('--accent-color', accentColorPalette.LightVibrant);
document.body.style.setProperty('--accent-color', accentColorPalette.LightVibrant);
document.body.style.color = accentColorPalette.LightVibrant;
}
else
{
progressBarFill.style.setProperty('--accent-color', color1);
document.body.style.setProperty('--accent-color', color1);
document.body.style.color = color1;
}
}
+31
View File
@@ -23,6 +23,37 @@
flex-shrink: 0;
}
#album-art-container.is-paused #album-art-layer,
#album-art-container.is-paused #album-art-transition-layer {
opacity: 0.7;
filter: grayscale(50%);
}
#pause-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease;
z-index: 10;
border-radius: inherit;
}
#pause-overlay svg {
height: 40%;
width: auto;
}
#album-art-container.is-paused #pause-overlay {
opacity: 1;
}
#album-art-layer,
#album-art-transition-layer {
position: absolute;
+5
View File
@@ -6,6 +6,11 @@
<div id="album-art-container">
<div id="album-art-layer"></div>
<div id="album-art-transition-layer"></div>
<div id="pause-overlay">
<svg viewBox="0 0 24 24" style="fill: var(--accent-color, #ffffff);">
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>
</svg>
</div>
</div>
<div id="song-info-wrapper">
+12 -4
View File
@@ -147,7 +147,7 @@ async function ChangeTrack(mediaProps, accentColorPalette) {
}, 250);
}
function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette) {
function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette, playbackStatus) {
// Update the label using your naming convention
currentTimeLabel.innerText =
ConvertMillisecondsToHoursMinutesSecondsSoItLooksBetterAndNotCringe(currentPositionMs);
@@ -155,6 +155,12 @@ function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette) {
durationLabel.innerText =
ConvertMillisecondsToHoursMinutesSecondsSoItLooksBetterAndNotCringe(timelineProps.EndTime);
// Set the pause overlay visibility based on playback status
if (playbackStatus === PlaybackStatus.PAUSED)
albumArtContainer.classList.add('is-paused');
else
albumArtContainer.classList.remove('is-paused');
// Set progressbar
// Ensure we don't divide by zero or exceed 100%
const durationMs = timelineProps.EndTime;
@@ -165,9 +171,11 @@ function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette) {
if (!useCustomColors) {
switch (themeVariant) {
case "matte":
progressBarFill.style.setProperty('--accent-color', accentColorPalette.DarkVibrant);
document.body.style.setProperty('--accent-color', accentColorPalette.DarkVibrant);
break;
case "matte-dark":
document.body.style.setProperty('--accent-color', accentColorPalette.LightVibrant);
break;
default:
progressBarFill.style.setProperty('--accent-color', accentColorPalette.LightVibrant);
break;
@@ -177,11 +185,11 @@ function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette) {
{
switch (themeVariant) {
case "matte":
progressBarFill.style.setProperty('--accent-color', color2);
document.body.style.setProperty('--accent-color', color2);
break;
// case "matte-dark":
default:
progressBarFill.style.setProperty('--accent-color', color1);
document.body.style.setProperty('--accent-color', color1);
break;
}
}
+30
View File
@@ -25,6 +25,36 @@
flex-shrink: 0;
}
#album-art-container.is-paused #album-art-layer,
#album-art-container.is-paused #album-art-transition-layer {
opacity: 0.2;
}
#pause-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease;
z-index: 10;
border-radius: inherit;
}
#pause-overlay svg {
height: 50%;
width: auto;
}
#album-art-container.is-paused #pause-overlay {
opacity: 1;
}
#album-art-layer,
#album-art-transition-layer {
position: absolute;
+50 -1
View File
@@ -8,6 +8,7 @@ const albumArtContainer = document.getElementById('album-art-container');
const albumArtLayer = document.getElementById('album-art-layer');
const albumArtTransition = document.getElementById('album-art-transition-layer');
const progressCircle = document.getElementById('progress-pie-circle');
const vinylContainer = document.getElementById('vinyl-container');
///////////////
// CONSTANTS //
@@ -60,7 +61,7 @@ async function ChangeTrack(mediaProps) {
}, 250);
}
function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette) {
function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette, playbackStatus) {
// Set progressbar
// Ensure we don't divide by zero or exceed 100%
const durationMs = timelineProps.EndTime;
@@ -75,4 +76,52 @@ function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette) {
// 0% progress = 157.1 offset. 100% progress = 0 offset.
const offset = circumference - (progressPercent / 100) * circumference;
progressCircle.style.strokeDashoffset = offset;
// Adjust 'Paused' check to match whatever string/value your backend sends
if (playbackStatus === PlaybackStatus.PAUSED)
setVinylPaused(true);
else
setVinylPaused(false);
}
const vinylAnimation = vinylContainer.animate(
[
{ transform: "rotate(0deg)" },
{ transform: "rotate(360deg)" }
],
{
duration: 10000,
iterations: Infinity,
easing: "linear"
}
);
let animationFrame;
function setVinylPaused(shouldPause) {
cancelAnimationFrame(animationFrame);
const from = vinylAnimation.playbackRate;
const to = shouldPause ? 0 : 1;
const duration = 700;
const start = performance.now();
vinylAnimation.play();
function update(now) {
const progress = Math.min((now - start) / duration, 1);
// Smooth acceleration/deceleration
const eased = progress * progress * (3 - 2 * progress);
vinylAnimation.playbackRate = from + (to - from) * eased;
if (progress < 1) {
animationFrame = requestAnimationFrame(update);
} else if (shouldPause) {
vinylAnimation.pause();
}
}
animationFrame = requestAnimationFrame(update);
}
+61 -4
View File
@@ -16,7 +16,7 @@
justify-content: center;
width: 100%;
filter: drop-shadow(0px 10px 15px rgba(0, 0, 0, 0.5));
animation: spin 10s linear infinite;
transition: transform 1.2s cubic-bezier(0.25, 1, 0.5, 1);
}
#vinyl-background {
@@ -91,7 +91,64 @@
transition: all 1s linear;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
@keyframes slide-in-from-top {
0% {
transform: translateY(-100%);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
@keyframes slide-in-from-top {
0% {
transform: translateY(-100%);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
@keyframes slide-out-top {
0% {
transform: translateY(0);
opacity: 1;
}
100% {
transform: translateY(-100%);
opacity: 0;
}
}
@keyframes slide-in-from-bottom {
0% {
transform: translateY(100%);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
@keyframes slide-out-bottom {
0% {
transform: translateY(0);
opacity: 1;
}
100% {
transform: translateY(100%);
opacity: 0;
}
}