From bd147b177279de1a644a615b2488f3907e3ace26 Mon Sep 17 00:00:00 2001 From: Bine Date: Tue, 8 Jul 2025 21:12:21 +0200 Subject: [PATCH 1/3] =?UTF-8?q?feat(lyrics-plus):=20change=20=E2=99=AA=20t?= =?UTF-8?q?o=20idle=20dots?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CustomApps/lyrics-plus/Pages.js | 49 ++++++++++++++++++++++++++-- CustomApps/lyrics-plus/style.css | 56 ++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/CustomApps/lyrics-plus/Pages.js b/CustomApps/lyrics-plus/Pages.js index 1b960236f6..d22efcd139 100755 --- a/CustomApps/lyrics-plus/Pages.js +++ b/CustomApps/lyrics-plus/Pages.js @@ -31,12 +31,32 @@ const IdlingIndicator = ({ isActive, progress, delay }) => { "--indicator-delay": `${delay}ms`, }, }, - react.createElement("div", { className: `lyrics-idling-indicator__circle ${progress >= 0.05 ? "active" : ""}` }), - react.createElement("div", { className: `lyrics-idling-indicator__circle ${progress >= 0.33 ? "active" : ""}` }), - react.createElement("div", { className: `lyrics-idling-indicator__circle ${progress >= 0.66 ? "active" : ""}` }) + [0.05, 0.33, 0.66].map((threshold) => + react.createElement( + "div", { className: `lyrics-idling-indicator__circle ${progress >= threshold ? "active" : ""}` } + ) + ) ); }; +const InlineIdlingIndicator = ({ progress, isActive }) => { + return react.createElement( + "span", + { + className: `lyrics-inline-idling-indicator${isActive ? " active" : ""}`, + }, + [0.05, 0.33, 0.66].map((threshold, idx) => + react.createElement( + "span", + { + key: idx, + className: `lyrics-inline-idling-dot${progress >= threshold ? " active" : ""}`, + } + ) + ) + ); +}; + const emptyLine = { startTime: 0, endTime: 0, @@ -145,6 +165,29 @@ const SyncedLyricsPage = react.memo(({ lyrics = [], provider, copyright, isKara delay: activeLines[2].startTime / 3, }); } + if (text === "♪") { + let className = "lyrics-lyricsContainer-LyricsLine"; + let ref; + if (Math.min(activeLineIndex, CONFIG.visual["lines-before"] + 1) === i) { + className += " lyrics-lyricsContainer-LyricsLine-active"; + ref = activeLineEle; + } + const animationIndex = activeLineIndex <= CONFIG.visual["lines-before"] + ? i - activeLineIndex + : i - CONFIG.visual["lines-before"] - 1; + const nextLine = activeLines[i + 1]; + const timeToNext = nextLine ? nextLine.startTime - startTime : 1000; + const progress = Math.min(1, (position - startTime) / (timeToNext || 1)); + return react.createElement( + "div", + { className, style: { cursor: "pointer", "--position-index": animationIndex, "--animation-index": (animationIndex < 0 ? 0 : animationIndex) + 1, "--blur-index": Math.abs(animationIndex) }, key: lineNumber, dir: "auto", ref, onClick: () => { if (startTime) Spicetify.Player.seek(startTime); } }, + react.createElement( + "p", + {}, + react.createElement(InlineIdlingIndicator, { progress, isActive: progress >= 1 }) + ) + ); + } let className = "lyrics-lyricsContainer-LyricsLine"; const activeElementIndex = Math.min(activeLineIndex, CONFIG.visual["lines-before"] + 1); diff --git a/CustomApps/lyrics-plus/style.css b/CustomApps/lyrics-plus/style.css index 298b2ddbe1..0539ee6288 100644 --- a/CustomApps/lyrics-plus/style.css +++ b/CustomApps/lyrics-plus/style.css @@ -728,3 +728,59 @@ div.lyrics-tabBar-headerItemLink { margin-left: 100px; } } + +.lyrics-inline-idling-indicator { + display: inline-flex; + align-items: center; + gap: 0.25em; + margin-left: 0.2em; + opacity: 0.5; + transition: opacity 0.2s; + vertical-align: middle; +} +.lyrics-inline-idling-indicator.active { + opacity: 1; +} +.lyrics-inline-idling-dot { + width: 0.5em; + height: 0.5em; + border-radius: 50%; + background: var(--lyrics-idling-dot-color, #888); + opacity: 0.3; + transform: scale(0.7); + transition: background 0.2s, opacity 0.2s, transform 0.2s; + display: inline-block; +} +.lyrics-inline-idling-dot.active { + background: var(--lyrics-idling-dot-active-color, #fff); + opacity: 1; + transform: scale(1.1); +} + +.lyrics-idling-indicator { + display: flex; + align-items: center; + gap: 0.4em; + justify-content: center; + margin: 0.5em 0; + opacity: 0.7; + transition: opacity 0.2s; +} +.lyrics-idling-indicator.active { + opacity: 1; +} +.lyrics-idling-dot { + width: 0.7em; + height: 0.7em; + border-radius: 50%; + background: var(--lyrics-idling-dot-color, #888); + opacity: 0.3; + transform: scale(0.7); + transition: background 0.2s, opacity 0.2s, transform 0.2s; + display: inline-block; +} +.lyrics-idling-dot.active { + background: var(--lyrics-idling-dot-active-color, #fff); + opacity: 1; + transform: scale(1.1); +} From 98c77014eda977c1f9dc8039d4af96725db81bc8 Mon Sep 17 00:00:00 2001 From: Bine Date: Tue, 8 Jul 2025 21:23:49 +0200 Subject: [PATCH 2/3] lint --- CustomApps/lyrics-plus/Pages.js | 119 ++++++++++++++++---------------- 1 file changed, 59 insertions(+), 60 deletions(-) diff --git a/CustomApps/lyrics-plus/Pages.js b/CustomApps/lyrics-plus/Pages.js index d22efcd139..0e13832db2 100755 --- a/CustomApps/lyrics-plus/Pages.js +++ b/CustomApps/lyrics-plus/Pages.js @@ -22,9 +22,8 @@ const IdlingIndicator = ({ isActive, progress, delay }) => { return react.createElement( "div", { - className: `lyrics-idling-indicator ${ - !isActive ? "lyrics-idling-indicator-hidden" : "" - } lyrics-lyricsContainer-LyricsLine lyrics-lyricsContainer-LyricsLine-active`, + className: `lyrics-idling-indicator ${!isActive ? "lyrics-idling-indicator-hidden" : "" + } lyrics-lyricsContainer-LyricsLine lyrics-lyricsContainer-LyricsLine-active`, style: { "--position-index": 0, "--animation-index": 1, @@ -32,29 +31,29 @@ const IdlingIndicator = ({ isActive, progress, delay }) => { }, }, [0.05, 0.33, 0.66].map((threshold) => - react.createElement( - "div", { className: `lyrics-idling-indicator__circle ${progress >= threshold ? "active" : ""}` } - ) - ) + react.createElement( + "div", { className: `lyrics-idling-indicator__circle ${progress >= threshold ? "active" : ""}` } + ) + ) ); }; const InlineIdlingIndicator = ({ progress, isActive }) => { - return react.createElement( - "span", - { - className: `lyrics-inline-idling-indicator${isActive ? " active" : ""}`, - }, - [0.05, 0.33, 0.66].map((threshold, idx) => - react.createElement( - "span", - { - key: idx, - className: `lyrics-inline-idling-dot${progress >= threshold ? " active" : ""}`, - } - ) - ) - ); + return react.createElement( + "span", + { + className: `lyrics-inline-idling-indicator${isActive ? " active" : ""}`, + }, + [0.05, 0.33, 0.66].map((threshold, idx) => + react.createElement( + "span", + { + key: idx, + className: `lyrics-inline-idling-dot${progress >= threshold ? " active" : ""}`, + } + ) + ) + ); }; const emptyLine = { @@ -253,21 +252,21 @@ const SyncedLyricsPage = react.memo(({ lyrics = [], provider, copyright, isKara !isKara ? lineText : react.createElement(KaraokeLine, { text, startTime, position, isActive }) ), belowMode && - react.createElement( - "p", - { - style: { - opacity: 0.5, - }, - onContextMenu: (event) => { - event.preventDefault(); - Spicetify.Platform.ClipboardAPI.copy(Utils.convertParsedToLRC(lyrics, belowMode).conver) - .then(() => Spicetify.showNotification("Translated lyrics copied to clipboard")) - .catch(() => Spicetify.showNotification("Failed to copy translated lyrics to clipboard")); - }, + react.createElement( + "p", + { + style: { + opacity: 0.5, }, - text - ) + onContextMenu: (event) => { + event.preventDefault(); + Spicetify.Platform.ClipboardAPI.copy(Utils.convertParsedToLRC(lyrics, belowMode).conver) + .then(() => Spicetify.showNotification("Translated lyrics copied to clipboard")) + .catch(() => Spicetify.showNotification("Failed to copy translated lyrics to clipboard")); + }, + }, + text + ) ); }) ), @@ -532,19 +531,19 @@ const SyncedExpandedLyricsPage = react.memo(({ lyrics, provider, copyright, isKa !isKara ? lineText : react.createElement(KaraokeLine, { text, startTime, position, isActive }) ), belowMode && - react.createElement( - "p", - { - style: { opacity: 0.5 }, - onContextMenu: (event) => { - event.preventDefault(); - Spicetify.Platform.ClipboardAPI.copy(Utils.convertParsedToLRC(lyrics, belowMode).conver) - .then(() => Spicetify.showNotification("Translated lyrics copied to clipboard")) - .catch(() => Spicetify.showNotification("Failed to copy translated lyrics to clipboard")); - }, + react.createElement( + "p", + { + style: { opacity: 0.5 }, + onContextMenu: (event) => { + event.preventDefault(); + Spicetify.Platform.ClipboardAPI.copy(Utils.convertParsedToLRC(lyrics, belowMode).conver) + .then(() => Spicetify.showNotification("Translated lyrics copied to clipboard")) + .catch(() => Spicetify.showNotification("Failed to copy translated lyrics to clipboard")); }, - text - ) + }, + text + ) ); }), react.createElement("p", { @@ -599,19 +598,19 @@ const UnsyncedLyricsPage = react.memo(({ lyrics, provider, copyright }) => { lineText ), belowMode && - react.createElement( - "p", - { - style: { opacity: 0.5 }, - onContextMenu: (event) => { - event.preventDefault(); - Spicetify.Platform.ClipboardAPI.copy(Utils.convertParsedToUnsynced(lyrics, belowMode).conver) - .then(() => Spicetify.showNotification("Translated lyrics copied to clipboard")) - .catch(() => Spicetify.showNotification("Failed to copy translated lyrics to clipboard")); - }, + react.createElement( + "p", + { + style: { opacity: 0.5 }, + onContextMenu: (event) => { + event.preventDefault(); + Spicetify.Platform.ClipboardAPI.copy(Utils.convertParsedToUnsynced(lyrics, belowMode).conver) + .then(() => Spicetify.showNotification("Translated lyrics copied to clipboard")) + .catch(() => Spicetify.showNotification("Failed to copy translated lyrics to clipboard")); }, - text - ) + }, + text + ) ); }), react.createElement("p", { From ce4b769f0711d3517f5563637a5784ce4a7d6275 Mon Sep 17 00:00:00 2001 From: Bine Date: Thu, 14 Aug 2025 20:55:13 +0200 Subject: [PATCH 3/3] Biome fix --- CustomApps/lyrics-plus/Pages.js | 122 ++++++++++++++++--------------- CustomApps/lyrics-plus/style.css | 82 +++++++++++---------- 2 files changed, 107 insertions(+), 97 deletions(-) diff --git a/CustomApps/lyrics-plus/Pages.js b/CustomApps/lyrics-plus/Pages.js index 0e13832db2..b31172ae71 100755 --- a/CustomApps/lyrics-plus/Pages.js +++ b/CustomApps/lyrics-plus/Pages.js @@ -22,8 +22,9 @@ const IdlingIndicator = ({ isActive, progress, delay }) => { return react.createElement( "div", { - className: `lyrics-idling-indicator ${!isActive ? "lyrics-idling-indicator-hidden" : "" - } lyrics-lyricsContainer-LyricsLine lyrics-lyricsContainer-LyricsLine-active`, + className: `lyrics-idling-indicator ${ + !isActive ? "lyrics-idling-indicator-hidden" : "" + } lyrics-lyricsContainer-LyricsLine lyrics-lyricsContainer-LyricsLine-active`, style: { "--position-index": 0, "--animation-index": 1, @@ -31,9 +32,7 @@ const IdlingIndicator = ({ isActive, progress, delay }) => { }, }, [0.05, 0.33, 0.66].map((threshold) => - react.createElement( - "div", { className: `lyrics-idling-indicator__circle ${progress >= threshold ? "active" : ""}` } - ) + react.createElement("div", { className: `lyrics-idling-indicator__circle ${progress >= threshold ? "active" : ""}` }) ) ); }; @@ -45,13 +44,10 @@ const InlineIdlingIndicator = ({ progress, isActive }) => { className: `lyrics-inline-idling-indicator${isActive ? " active" : ""}`, }, [0.05, 0.33, 0.66].map((threshold, idx) => - react.createElement( - "span", - { - key: idx, - className: `lyrics-inline-idling-dot${progress >= threshold ? " active" : ""}`, - } - ) + react.createElement("span", { + key: idx, + className: `lyrics-inline-idling-dot${progress >= threshold ? " active" : ""}`, + }) ) ); }; @@ -171,20 +167,28 @@ const SyncedLyricsPage = react.memo(({ lyrics = [], provider, copyright, isKara className += " lyrics-lyricsContainer-LyricsLine-active"; ref = activeLineEle; } - const animationIndex = activeLineIndex <= CONFIG.visual["lines-before"] - ? i - activeLineIndex - : i - CONFIG.visual["lines-before"] - 1; + const animationIndex = activeLineIndex <= CONFIG.visual["lines-before"] ? i - activeLineIndex : i - CONFIG.visual["lines-before"] - 1; const nextLine = activeLines[i + 1]; const timeToNext = nextLine ? nextLine.startTime - startTime : 1000; const progress = Math.min(1, (position - startTime) / (timeToNext || 1)); return react.createElement( "div", - { className, style: { cursor: "pointer", "--position-index": animationIndex, "--animation-index": (animationIndex < 0 ? 0 : animationIndex) + 1, "--blur-index": Math.abs(animationIndex) }, key: lineNumber, dir: "auto", ref, onClick: () => { if (startTime) Spicetify.Player.seek(startTime); } }, - react.createElement( - "p", - {}, - react.createElement(InlineIdlingIndicator, { progress, isActive: progress >= 1 }) - ) + { + className, + style: { + cursor: "pointer", + "--position-index": animationIndex, + "--animation-index": (animationIndex < 0 ? 0 : animationIndex) + 1, + "--blur-index": Math.abs(animationIndex), + }, + key: lineNumber, + dir: "auto", + ref, + onClick: () => { + if (startTime) Spicetify.Player.seek(startTime); + }, + }, + react.createElement("p", {}, react.createElement(InlineIdlingIndicator, { progress, isActive: progress >= 1 })) ); } @@ -252,21 +256,21 @@ const SyncedLyricsPage = react.memo(({ lyrics = [], provider, copyright, isKara !isKara ? lineText : react.createElement(KaraokeLine, { text, startTime, position, isActive }) ), belowMode && - react.createElement( - "p", - { - style: { - opacity: 0.5, - }, - onContextMenu: (event) => { - event.preventDefault(); - Spicetify.Platform.ClipboardAPI.copy(Utils.convertParsedToLRC(lyrics, belowMode).conver) - .then(() => Spicetify.showNotification("Translated lyrics copied to clipboard")) - .catch(() => Spicetify.showNotification("Failed to copy translated lyrics to clipboard")); + react.createElement( + "p", + { + style: { + opacity: 0.5, + }, + onContextMenu: (event) => { + event.preventDefault(); + Spicetify.Platform.ClipboardAPI.copy(Utils.convertParsedToLRC(lyrics, belowMode).conver) + .then(() => Spicetify.showNotification("Translated lyrics copied to clipboard")) + .catch(() => Spicetify.showNotification("Failed to copy translated lyrics to clipboard")); + }, }, - }, - text - ) + text + ) ); }) ), @@ -531,19 +535,19 @@ const SyncedExpandedLyricsPage = react.memo(({ lyrics, provider, copyright, isKa !isKara ? lineText : react.createElement(KaraokeLine, { text, startTime, position, isActive }) ), belowMode && - react.createElement( - "p", - { - style: { opacity: 0.5 }, - onContextMenu: (event) => { - event.preventDefault(); - Spicetify.Platform.ClipboardAPI.copy(Utils.convertParsedToLRC(lyrics, belowMode).conver) - .then(() => Spicetify.showNotification("Translated lyrics copied to clipboard")) - .catch(() => Spicetify.showNotification("Failed to copy translated lyrics to clipboard")); + react.createElement( + "p", + { + style: { opacity: 0.5 }, + onContextMenu: (event) => { + event.preventDefault(); + Spicetify.Platform.ClipboardAPI.copy(Utils.convertParsedToLRC(lyrics, belowMode).conver) + .then(() => Spicetify.showNotification("Translated lyrics copied to clipboard")) + .catch(() => Spicetify.showNotification("Failed to copy translated lyrics to clipboard")); + }, }, - }, - text - ) + text + ) ); }), react.createElement("p", { @@ -598,19 +602,19 @@ const UnsyncedLyricsPage = react.memo(({ lyrics, provider, copyright }) => { lineText ), belowMode && - react.createElement( - "p", - { - style: { opacity: 0.5 }, - onContextMenu: (event) => { - event.preventDefault(); - Spicetify.Platform.ClipboardAPI.copy(Utils.convertParsedToUnsynced(lyrics, belowMode).conver) - .then(() => Spicetify.showNotification("Translated lyrics copied to clipboard")) - .catch(() => Spicetify.showNotification("Failed to copy translated lyrics to clipboard")); + react.createElement( + "p", + { + style: { opacity: 0.5 }, + onContextMenu: (event) => { + event.preventDefault(); + Spicetify.Platform.ClipboardAPI.copy(Utils.convertParsedToUnsynced(lyrics, belowMode).conver) + .then(() => Spicetify.showNotification("Translated lyrics copied to clipboard")) + .catch(() => Spicetify.showNotification("Failed to copy translated lyrics to clipboard")); + }, }, - }, - text - ) + text + ) ); }), react.createElement("p", { diff --git a/CustomApps/lyrics-plus/style.css b/CustomApps/lyrics-plus/style.css index 0539ee6288..0028cf908a 100644 --- a/CustomApps/lyrics-plus/style.css +++ b/CustomApps/lyrics-plus/style.css @@ -730,57 +730,63 @@ div.lyrics-tabBar-headerItemLink { } .lyrics-inline-idling-indicator { - display: inline-flex; - align-items: center; - gap: 0.25em; - margin-left: 0.2em; - opacity: 0.5; - transition: opacity 0.2s; - vertical-align: middle; + display: inline-flex; + align-items: center; + gap: 0.25em; + margin-left: 0.2em; + opacity: 0.5; + transition: opacity 0.2s; + vertical-align: middle; } .lyrics-inline-idling-indicator.active { - opacity: 1; + opacity: 1; } .lyrics-inline-idling-dot { - width: 0.5em; - height: 0.5em; - border-radius: 50%; - background: var(--lyrics-idling-dot-color, #888); - opacity: 0.3; - transform: scale(0.7); - transition: background 0.2s, opacity 0.2s, transform 0.2s; - display: inline-block; + width: 0.5em; + height: 0.5em; + border-radius: 50%; + background: var(--lyrics-idling-dot-color, #888); + opacity: 0.3; + transform: scale(0.7); + transition: + background 0.2s, + opacity 0.2s, + transform 0.2s; + display: inline-block; } .lyrics-inline-idling-dot.active { - background: var(--lyrics-idling-dot-active-color, #fff); - opacity: 1; - transform: scale(1.1); + background: var(--lyrics-idling-dot-active-color, #fff); + opacity: 1; + transform: scale(1.1); } .lyrics-idling-indicator { - display: flex; - align-items: center; - gap: 0.4em; - justify-content: center; - margin: 0.5em 0; - opacity: 0.7; - transition: opacity 0.2s; + display: flex; + align-items: center; + gap: 0.4em; + justify-content: center; + margin: 0.5em 0; + opacity: 0.7; + transition: opacity 0.2s; } .lyrics-idling-indicator.active { - opacity: 1; + opacity: 1; } .lyrics-idling-dot { - width: 0.7em; - height: 0.7em; - border-radius: 50%; - background: var(--lyrics-idling-dot-color, #888); - opacity: 0.3; - transform: scale(0.7); - transition: background 0.2s, opacity 0.2s, transform 0.2s; - display: inline-block; + width: 0.7em; + height: 0.7em; + border-radius: 50%; + background: var(--lyrics-idling-dot-color, #888); + opacity: 0.3; + transform: scale(0.7); + transition: + background 0.2s, + opacity 0.2s, + transform 0.2s; + display: inline-block; } .lyrics-idling-dot.active { - background: var(--lyrics-idling-dot-active-color, #fff); - opacity: 1; - transform: scale(1.1); + background: var(--lyrics-idling-dot-active-color, #fff); + opacity: 1; + transform: scale(1.1); }