Merge pull request #61 from meowarex/dev

Merged Obsidian into RL + Added Conditional Settings Visability
This commit is contained in:
Meow Meow
2026-02-11 20:56:54 +11:00
committed by GitHub
4 changed files with 561 additions and 84 deletions
Submodule Reference/luna-plugins deleted from 29204beb93
+468 -80
View File
@@ -2,11 +2,29 @@ import { ReactiveStore } from "@luna/core";
import { LunaSettings, LunaSwitchSetting, LunaNumberSetting } from "@luna/ui"; import { LunaSettings, LunaSwitchSetting, LunaNumberSetting } from "@luna/ui";
import React from "react"; import React from "react";
declare global {
interface Window {
updateRadiantLyricsStyles?: () => void;
updateRadiantLyricsTextGlow?: () => void;
updateStickyLyricsFeature?: () => void;
updateRadiantLyricsPlayerBarTint?: () => void;
updateRadiantLyricsGlobalBackground?: () => void;
updateRadiantLyricsNowPlayingBackground?: () => void;
updateStickyLyricsIcon?: () => void;
}
}
export const settings = await ReactiveStore.getPluginStorage("RadiantLyrics", { export const settings = await ReactiveStore.getPluginStorage("RadiantLyrics", {
lyricsGlowEnabled: true, lyricsGlowEnabled: true,
trackTitleGlow: false, trackTitleGlow: false,
hideUIEnabled: true, hideUIEnabled: true,
playerBarVisible: false, playerBarVisible: false,
floatingPlayerBar: true,
playerBarTint: 5,
playerBarTintColor: "#000000" as string,
playerBarTintCustomColors: [] as string[],
playerBarRadius: 5,
playerBarSpacing: 10,
CoverEverywhere: true, CoverEverywhere: true,
performanceMode: false, performanceMode: false,
spinningArt: true, spinningArt: true,
@@ -64,6 +82,27 @@ export const Settings = () => {
const [backgroundRadius, setBackgroundRadius] = React.useState( const [backgroundRadius, setBackgroundRadius] = React.useState(
settings.backgroundRadius, settings.backgroundRadius,
); );
const [floatingPlayerBar, setFloatingPlayerBar] = React.useState(
settings.floatingPlayerBar,
);
const [playerBarTint, setPlayerBarTint] = React.useState(
settings.playerBarTint,
);
const [playerBarTintColor, setPlayerBarTintColor] = React.useState(
settings.playerBarTintColor,
);
const [playerBarRadius, setPlayerBarRadius] = React.useState(
settings.playerBarRadius,
);
const [playerBarSpacing, setPlayerBarSpacing] = React.useState(
settings.playerBarSpacing,
);
const [showTintColorPicker, setShowTintColorPicker] = React.useState(false);
const [isTintAnimatingIn, setIsTintAnimatingIn] = React.useState(false);
const [shouldRenderTintPicker, setShouldRenderTintPicker] = React.useState(false);
const [tintCustomInput, setTintCustomInput] = React.useState(settings.playerBarTintColor);
const [tintCustomColors, setTintCustomColors] = React.useState(settings.playerBarTintCustomColors);
const [tintHoveredColorIndex, setTintHoveredColorIndex] = React.useState<number | null>(null);
const [stickyLyricsFeature, setStickyLyricsFeature] = React.useState( const [stickyLyricsFeature, setStickyLyricsFeature] = React.useState(
settings.stickyLyricsFeature, settings.stickyLyricsFeature,
); );
@@ -85,10 +124,11 @@ export const Settings = () => {
desc="Enable glowing effect for lyrics & Font Styling Changes" desc="Enable glowing effect for lyrics & Font Styling Changes"
checked={lyricsGlowEnabled} checked={lyricsGlowEnabled}
onChange={(_: unknown, checked: boolean) => { onChange={(_: unknown, checked: boolean) => {
setLyricsGlowEnabled((settings.lyricsGlowEnabled = checked)); settings.lyricsGlowEnabled = checked;
setLyricsGlowEnabled(checked);
// Update styles immediately when setting changes // Update styles immediately when setting changes
if ((window as any).updateRadiantLyricsStyles) { if (window.updateRadiantLyricsStyles) {
(window as any).updateRadiantLyricsStyles(); window.updateRadiantLyricsStyles();
} }
}} }}
/> />
@@ -97,20 +137,40 @@ export const Settings = () => {
desc="Apply glow to the track title" desc="Apply glow to the track title"
checked={trackTitleGlow} checked={trackTitleGlow}
onChange={(_: unknown, checked: boolean) => { onChange={(_: unknown, checked: boolean) => {
setTrackTitleGlow((settings.trackTitleGlow = checked)); settings.trackTitleGlow = checked;
if ((window as any).updateRadiantLyricsStyles) { setTrackTitleGlow(checked);
(window as any).updateRadiantLyricsStyles(); if (window.updateRadiantLyricsStyles) {
window.updateRadiantLyricsStyles();
} }
}} }}
/> />
{(lyricsGlowEnabled || trackTitleGlow) && (
<LunaNumberSetting
title="Text Glow"
desc="Adjust the glow size of lyrics (0-100, default: 20)"
min={0}
max={100}
step={1}
value={textGlow}
onNumber={(value: number) => {
settings.textGlow = value;
setTextGlow(value);
// Update variables immediately when setting changes
if (window.updateRadiantLyricsTextGlow) {
window.updateRadiantLyricsTextGlow();
}
}}
/>
)}
<AnySwitch <AnySwitch
title="Sticky Lyrics" title="Sticky Lyrics"
desc="Adds a dropdown to the Lyrics tab that auto-switches to Play Queue when lyrics aren't available" desc="Adds a dropdown to the Lyrics tab that auto-switches to Play Queue when lyrics aren't available"
checked={stickyLyricsFeature} checked={stickyLyricsFeature}
onChange={(_: unknown, checked: boolean) => { onChange={(_: unknown, checked: boolean) => {
setStickyLyricsFeature((settings.stickyLyricsFeature = checked)); settings.stickyLyricsFeature = checked;
if ((window as any).updateStickyLyricsFeature) { setStickyLyricsFeature(checked);
(window as any).updateStickyLyricsFeature(); if (window.updateStickyLyricsFeature) {
window.updateStickyLyricsFeature();
} }
}} }}
/> />
@@ -119,22 +179,341 @@ export const Settings = () => {
desc="Enable hide/unhide UI functionality with toggle buttons" desc="Enable hide/unhide UI functionality with toggle buttons"
checked={hideUIEnabled} checked={hideUIEnabled}
onChange={(_: unknown, checked: boolean) => { onChange={(_: unknown, checked: boolean) => {
setHideUIEnabled((settings.hideUIEnabled = checked)); settings.hideUIEnabled = checked;
setHideUIEnabled(checked);
}} }}
/> />
{hideUIEnabled && (
<AnySwitch <AnySwitch
title="Player Bar Visibility in Hide UI Mode" title="Player Bar Visibility in Hide UI Mode"
desc="Keep player bar visible when UI is hidden" desc="Keep player bar visible when UI is hidden"
checked={playerBarVisible} checked={playerBarVisible}
onChange={(_: unknown, checked: boolean) => { onChange={(_: unknown, checked: boolean) => {
console.log("Player Bar Visibility:", checked ? "visible" : "hidden"); console.log("Player Bar Visibility:", checked ? "visible" : "hidden");
setPlayerBarVisible((settings.playerBarVisible = checked)); settings.playerBarVisible = checked;
setPlayerBarVisible(checked);
// Update styles immediately when setting changes // Update styles immediately when setting changes
if ((window as any).updateRadiantLyricsStyles) { if (window.updateRadiantLyricsStyles) {
(window as any).updateRadiantLyricsStyles(); window.updateRadiantLyricsStyles();
} }
}} }}
/> />
)}
<AnySwitch
title="Floating Player Bar"
desc="Floating rounded player bar with backdrop blur"
checked={floatingPlayerBar}
onChange={(_: unknown, checked: boolean) => {
settings.floatingPlayerBar = checked;
setFloatingPlayerBar(checked);
if (window.updateRadiantLyricsStyles) {
window.updateRadiantLyricsStyles();
}
}}
/>
{floatingPlayerBar && (
<>
<LunaNumberSetting
title="Floating Bar Corner Radius"
desc="Adjust the corner rounding of the player bar (0-50, default: 5)"
min={0}
max={50}
step={1}
value={playerBarRadius}
onNumber={(value: number) => {
settings.playerBarRadius = value;
setPlayerBarRadius(value);
window.updateRadiantLyricsPlayerBarTint?.();
}}
/>
<LunaNumberSetting
title="Floating Bar Spacing"
desc="Adjust the spacing of the player bar from the edges (0-50, default: 10)"
min={0}
max={50}
step={1}
value={playerBarSpacing}
onNumber={(value: number) => {
settings.playerBarSpacing = value;
setPlayerBarSpacing(value);
window.updateRadiantLyricsPlayerBarTint?.();
}}
/>
</>
)}
{(() => {
const closeTintColorPicker = () => {
setIsTintAnimatingIn(false);
setTimeout(() => {
setShowTintColorPicker(false);
setShouldRenderTintPicker(false);
}, 200);
};
const openTintColorPicker = () => {
setShowTintColorPicker(true);
setShouldRenderTintPicker(true);
setTimeout(() => setIsTintAnimatingIn(true), 10);
};
const updateTintColor = (color: string) => {
setPlayerBarTintColor(color);
setTintCustomInput(color);
settings.playerBarTintColor = color;
window.updateRadiantLyricsPlayerBarTint?.();
};
const addTintCustomColor = () => {
if (tintCustomInput) {
const trimmedInput = tintCustomInput.trim().toLowerCase();
const hexColorRegex = /^#([0-9a-f]{6}|[0-9a-f]{3})$/i;
if (
hexColorRegex.test(trimmedInput) &&
!tintColorPresets.includes(trimmedInput) &&
!tintCustomColors.includes(trimmedInput)
) {
const newCustomColors = [...tintCustomColors, trimmedInput];
setTintCustomColors(newCustomColors);
settings.playerBarTintCustomColors = newCustomColors;
}
}
};
const removeTintCustomColor = (colorToRemove: string) => {
const newCustomColors = tintCustomColors.filter(
(color) => color !== colorToRemove,
);
setTintCustomColors(newCustomColors);
settings.playerBarTintCustomColors = newCustomColors;
if (playerBarTintColor === colorToRemove) {
updateTintColor("#000000");
}
};
const tintColorPresets = [
"#000000", "#111111", "#222222", "#333333", "#444444",
"#555555", "#666666", "#888888", "#aaaaaa", "#cccccc",
"#ffffff", "#0d1117", "#1a1a2e", "#16213e", "#0f3460",
"#1b1b2f", "#162447", "#1f4068", "#e94560",
];
const allTintColors = [...tintColorPresets, ...tintCustomColors];
return (
<div style={{ position: "relative" }}>
<LunaNumberSetting
title="Player Bar Tint"
desc="Tint color & opacity (0-10, default: 5)"
min={0}
max={10}
step={1}
value={playerBarTint}
onNumber={(value: number) => {
settings.playerBarTint = value;
setPlayerBarTint(value);
window.updateRadiantLyricsPlayerBarTint?.();
}}
/>
{/* Color swatch — positioned just left of the value box */}
<button
type="button"
onClick={() => showTintColorPicker ? closeTintColorPicker() : openTintColorPicker()}
style={{
width: "28px",
height: "28px",
border: "1px solid rgba(255,255,255,0.15)",
borderRadius: "6px",
cursor: "pointer",
background: playerBarTintColor,
position: "absolute",
right: "135px",
top: "50%",
transform: "translateY(-50%)",
overflow: "hidden",
zIndex: 1,
}}
>
<div style={{ position: "absolute", inset: 0, background: "rgba(0,0,0,0.1)", backdropFilter: "blur(2px)" }} />
</button>
{/* Color Picker Modal */}
{shouldRenderTintPicker && (
<>
<button
type="button"
aria-label="Close color picker"
onClick={closeTintColorPicker}
style={{
position: "fixed",
top: 0, left: 0, right: 0, bottom: 0,
background: "rgba(0,0,0,0.6)",
zIndex: 1000,
opacity: isTintAnimatingIn ? 1 : 0,
transition: "opacity 0.2s ease",
border: "none",
padding: 0,
cursor: "default",
width: "100%",
}}
/>
<div
style={{
position: "fixed",
top: "50%",
left: "50%",
background: "rgba(20,20,20,0.98)",
backdropFilter: "blur(20px)",
WebkitBackdropFilter: "blur(20px)",
border: "1px solid rgba(255,255,255,0.15)",
borderRadius: "16px",
padding: "20px",
minWidth: "320px",
maxWidth: "90vw",
maxHeight: "90vh",
zIndex: 1001,
boxShadow: "0 20px 40px rgba(0,0,0,0.7)",
opacity: isTintAnimatingIn ? 1 : 0,
transform: isTintAnimatingIn
? "translate(-50%, -50%) scale(1)"
: "translate(-50%, -50%) scale(0.9)",
transition: "all 0.2s ease",
}}
>
<div style={{ marginBottom: "12px", color: "#fff", fontWeight: "bold", fontSize: "14px" }}>
Choose Tint Color
</div>
<div style={{ display: "grid", gridTemplateColumns: "repeat(7, 1fr)", gap: "8px", marginBottom: "16px" }}>
{allTintColors.map((color, index) => {
const isCustomColor = tintCustomColors.includes(color);
const isHovered = tintHoveredColorIndex === index;
return (
// biome-ignore lint/a11y/noStaticElementInteractions: cosmetic hover tracking on wrapper containing interactive buttons
<div
key={color}
style={{ position: "relative", width: "32px", height: "32px", cursor: "pointer" }}
onMouseEnter={() => setTintHoveredColorIndex(index)}
onMouseLeave={() => setTintHoveredColorIndex(null)}
>
<button
type="button"
onClick={() => { updateTintColor(color); closeTintColorPicker(); }}
style={{
width: "100%",
height: "100%",
borderRadius: "6px",
border: playerBarTintColor === color
? "2px solid #fff"
: "1px solid rgba(255,255,255,0.2)",
background: color,
cursor: "pointer",
transition: "all 0.2s ease",
}}
/>
{isCustomColor && (
<button
type="button"
onClick={(e) => { e.stopPropagation(); removeTintCustomColor(color); }}
style={{
position: "absolute",
top: "-4px", right: "-4px",
width: "16px", height: "16px",
borderRadius: "50%",
border: "1px solid rgba(255,255,255,0.8)",
background: "rgba(0,0,0,0.8)",
color: "#fff",
cursor: "pointer",
fontSize: "10px",
display: "flex",
alignItems: "center",
justifyContent: "center",
opacity: isHovered ? 1 : 0,
transition: "opacity 0.2s ease",
zIndex: 10,
}}
>
×
</button>
)}
</div>
);
})}
</div>
<div style={{ marginBottom: "12px" }}>
<div style={{ color: "rgba(255,255,255,0.7)", fontSize: "12px", marginBottom: "6px" }}>
Add Custom Color
</div>
<div style={{ display: "flex", gap: "8px", alignItems: "center" }}>
<input
type="text"
value={tintCustomInput}
onChange={(e) => setTintCustomInput(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter") {
updateTintColor(tintCustomInput);
addTintCustomColor();
}
}}
placeholder="#000000"
style={{
flex: 1,
padding: "8px 12px",
borderRadius: "6px",
border: "1px solid rgba(255,255,255,0.2)",
background: "rgba(255,255,255,0.1)",
color: "#fff",
fontSize: "14px",
fontFamily: "monospace",
boxSizing: "border-box",
}}
/>
<button
type="button"
onClick={() => { updateTintColor(tintCustomInput); addTintCustomColor(); }}
style={{
width: "32px", height: "32px",
borderRadius: "6px",
border: "1px solid rgba(255,255,255,0.3)",
background: "rgba(255,255,255,0.15)",
color: "#fff",
cursor: "pointer",
fontSize: "16px",
display: "flex",
alignItems: "center",
justifyContent: "center",
transition: "all 0.2s ease",
}}
onMouseEnter={(e) => { e.currentTarget.style.background = "rgba(255,255,255,0.25)"; }}
onMouseLeave={(e) => { e.currentTarget.style.background = "rgba(255,255,255,0.15)"; }}
>
+
</button>
</div>
</div>
<button
type="button"
onClick={closeTintColorPicker}
style={{
width: "100%",
padding: "8px",
borderRadius: "6px",
border: "1px solid rgba(255,255,255,0.2)",
background: "rgba(255,255,255,0.1)",
color: "#fff",
cursor: "pointer",
fontSize: "12px",
}}
>
Done
</button>
</div>
</>
)}
</div>
);
})()}
<AnySwitch <AnySwitch
title="Cover Everywhere" title="Cover Everywhere"
desc="Apply the spinning Cover Art background to the entire app, not just the Now Playing view, Heavily Inspired by Cover-Theme by @Inrixia" desc="Apply the spinning Cover Art background to the entire app, not just the Now Playing view, Heavily Inspired by Cover-Theme by @Inrixia"
@@ -144,31 +523,34 @@ export const Settings = () => {
"Spinning Cover Everywhere:", "Spinning Cover Everywhere:",
checked ? "enabled" : "disabled", checked ? "enabled" : "disabled",
); );
setCoverEverywhere( settings.CoverEverywhere = checked;
(settings.CoverEverywhere = checked), setCoverEverywhere(checked);
);
// Update styles immediately when setting changes // Update styles immediately when setting changes
if ((window as any).updateRadiantLyricsGlobalBackground) { if (window.updateRadiantLyricsGlobalBackground) {
(window as any).updateRadiantLyricsGlobalBackground(); window.updateRadiantLyricsGlobalBackground();
} }
}} }}
/> />
{CoverEverywhere && (
<AnySwitch <AnySwitch
title="Performance Mode | Experimental" title="Performance Mode | Experimental"
desc="Performance mode: Reduces blur effects & uses smaller image sizes, to optimize GPU usage" desc="Performance mode: Reduces blur effects & uses smaller image sizes, to optimize GPU usage"
checked={performanceMode} checked={performanceMode}
onChange={(_: unknown, checked: boolean) => { onChange={(_: unknown, checked: boolean) => {
console.log("Performance Mode:", checked ? "enabled" : "disabled"); console.log("Performance Mode:", checked ? "enabled" : "disabled");
setPerformanceMode((settings.performanceMode = checked)); settings.performanceMode = checked;
setPerformanceMode(checked);
// Update background animations immediately when setting changes // Update background animations immediately when setting changes
if ((window as any).updateRadiantLyricsGlobalBackground) { if (window.updateRadiantLyricsGlobalBackground) {
(window as any).updateRadiantLyricsGlobalBackground(); window.updateRadiantLyricsGlobalBackground();
} }
if ((window as any).updateRadiantLyricsNowPlayingBackground) { if (window.updateRadiantLyricsNowPlayingBackground) {
(window as any).updateRadiantLyricsNowPlayingBackground(); window.updateRadiantLyricsNowPlayingBackground();
} }
}} }}
/> />
)}
{CoverEverywhere && (
<AnySwitch <AnySwitch
title="Background Cover Spin" // Cheers @Max/n0201 for the idea <3 title="Background Cover Spin" // Cheers @Max/n0201 for the idea <3
desc="Enable the spinning cover art background animation" desc="Enable the spinning cover art background animation"
@@ -178,73 +560,67 @@ export const Settings = () => {
"Background Cover Spin:", "Background Cover Spin:",
checked ? "enabled" : "disabled", checked ? "enabled" : "disabled",
); );
setspinningArt((settings.spinningArt = checked)); settings.spinningArt = checked;
if ((window as any).updateRadiantLyricsGlobalBackground) { setspinningArt(checked);
(window as any).updateRadiantLyricsGlobalBackground(); if (window.updateRadiantLyricsGlobalBackground) {
window.updateRadiantLyricsGlobalBackground();
} }
if ( if (
settings.settingsAffectNowPlaying && settings.settingsAffectNowPlaying &&
(window as any).updateRadiantLyricsNowPlayingBackground window.updateRadiantLyricsNowPlayingBackground
) { ) {
(window as any).updateRadiantLyricsNowPlayingBackground(); window.updateRadiantLyricsNowPlayingBackground();
}
}}
/>
<LunaNumberSetting
title="Text Glow"
desc="Adjust the glow size of lyrics (0-100, default: 20)"
min={0}
max={100}
step={1}
value={textGlow}
onNumber={(value: number) => {
setTextGlow((settings.textGlow = value));
// Update variables immediately when setting changes
if ((window as any).updateRadiantLyricsTextGlow) {
(window as any).updateRadiantLyricsTextGlow();
} }
}} }}
/> />
)}
{CoverEverywhere && (
<LunaNumberSetting <LunaNumberSetting
title="Background Scale" title="Background Scale"
desc="Adjust the scale of the background cover (1=10% - 50=500%)" desc="Adjust the scale of the background cover (1=10% - 50=500%, default: 15)"
min={1} min={1}
max={50} max={50}
step={1} step={1}
value={backgroundScale} value={backgroundScale}
onNumber={(value: number) => { onNumber={(value: number) => {
setBackgroundScale((settings.backgroundScale = value)); settings.backgroundScale = value;
if ((window as any).updateRadiantLyricsGlobalBackground) { setBackgroundScale(value);
(window as any).updateRadiantLyricsGlobalBackground(); if (window.updateRadiantLyricsGlobalBackground) {
window.updateRadiantLyricsGlobalBackground();
} }
if ( if (
settings.settingsAffectNowPlaying && settings.settingsAffectNowPlaying &&
(window as any).updateRadiantLyricsNowPlayingBackground window.updateRadiantLyricsNowPlayingBackground
) { ) {
(window as any).updateRadiantLyricsNowPlayingBackground(); window.updateRadiantLyricsNowPlayingBackground();
} }
}} }}
/> />
)}
{CoverEverywhere && (
<LunaNumberSetting <LunaNumberSetting
title="Background Radius" title="Background Radius"
desc="Adjust the cover art corner radius (0-100%, 100% = circle)" desc="Adjust the cover art corner radius (0-100%, default: 25)"
min={0} min={0}
max={100} max={100}
step={1} step={1}
value={backgroundRadius} value={backgroundRadius}
onNumber={(value: number) => { onNumber={(value: number) => {
setBackgroundRadius((settings.backgroundRadius = value)); settings.backgroundRadius = value;
if ((window as any).updateRadiantLyricsGlobalBackground) { setBackgroundRadius(value);
(window as any).updateRadiantLyricsGlobalBackground(); if (window.updateRadiantLyricsGlobalBackground) {
window.updateRadiantLyricsGlobalBackground();
} }
if ( if (
settings.settingsAffectNowPlaying && settings.settingsAffectNowPlaying &&
(window as any).updateRadiantLyricsNowPlayingBackground window.updateRadiantLyricsNowPlayingBackground
) { ) {
(window as any).updateRadiantLyricsNowPlayingBackground(); window.updateRadiantLyricsNowPlayingBackground();
} }
}} }}
/> />
)}
{CoverEverywhere && (
<LunaNumberSetting <LunaNumberSetting
title="Background Contrast" title="Background Contrast"
desc="Adjust the contrast of the spinning background (0-200, default: 120)" desc="Adjust the contrast of the spinning background (0-200, default: 120)"
@@ -253,18 +629,21 @@ export const Settings = () => {
step={1} step={1}
value={backgroundContrast} value={backgroundContrast}
onNumber={(value: number) => { onNumber={(value: number) => {
setBackgroundContrast((settings.backgroundContrast = value)); settings.backgroundContrast = value;
if ((window as any).updateRadiantLyricsGlobalBackground) { setBackgroundContrast(value);
(window as any).updateRadiantLyricsGlobalBackground(); if (window.updateRadiantLyricsGlobalBackground) {
window.updateRadiantLyricsGlobalBackground();
} }
if ( if (
settings.settingsAffectNowPlaying && settings.settingsAffectNowPlaying &&
(window as any).updateRadiantLyricsNowPlayingBackground window.updateRadiantLyricsNowPlayingBackground
) { ) {
(window as any).updateRadiantLyricsNowPlayingBackground(); window.updateRadiantLyricsNowPlayingBackground();
} }
}} }}
/> />
)}
{CoverEverywhere && (
<LunaNumberSetting <LunaNumberSetting
title="Background Blur" title="Background Blur"
desc="Adjust the blur amount of the spinning background (0-200, default: 80)" desc="Adjust the blur amount of the spinning background (0-200, default: 80)"
@@ -274,18 +653,21 @@ export const Settings = () => {
value={backgroundBlur} value={backgroundBlur}
onNumber={(value: number) => { onNumber={(value: number) => {
console.log("Background Blur:", value); console.log("Background Blur:", value);
setBackgroundBlur((settings.backgroundBlur = value)); settings.backgroundBlur = value;
if ((window as any).updateRadiantLyricsGlobalBackground) { setBackgroundBlur(value);
(window as any).updateRadiantLyricsGlobalBackground(); if (window.updateRadiantLyricsGlobalBackground) {
window.updateRadiantLyricsGlobalBackground();
} }
if ( if (
settings.settingsAffectNowPlaying && settings.settingsAffectNowPlaying &&
(window as any).updateRadiantLyricsNowPlayingBackground window.updateRadiantLyricsNowPlayingBackground
) { ) {
(window as any).updateRadiantLyricsNowPlayingBackground(); window.updateRadiantLyricsNowPlayingBackground();
} }
}} }}
/> />
)}
{CoverEverywhere && (
<LunaNumberSetting <LunaNumberSetting
title="Background Brightness" title="Background Brightness"
desc="Adjust the brightness of the spinning background (0-100, default: 40)" desc="Adjust the brightness of the spinning background (0-100, default: 40)"
@@ -295,18 +677,21 @@ export const Settings = () => {
value={backgroundBrightness} value={backgroundBrightness}
onNumber={(value: number) => { onNumber={(value: number) => {
console.log("Background Brightness:", value); console.log("Background Brightness:", value);
setBackgroundBrightness((settings.backgroundBrightness = value)); settings.backgroundBrightness = value;
if ((window as any).updateRadiantLyricsGlobalBackground) { setBackgroundBrightness(value);
(window as any).updateRadiantLyricsGlobalBackground(); if (window.updateRadiantLyricsGlobalBackground) {
window.updateRadiantLyricsGlobalBackground();
} }
if ( if (
settings.settingsAffectNowPlaying && settings.settingsAffectNowPlaying &&
(window as any).updateRadiantLyricsNowPlayingBackground window.updateRadiantLyricsNowPlayingBackground
) { ) {
(window as any).updateRadiantLyricsNowPlayingBackground(); window.updateRadiantLyricsNowPlayingBackground();
} }
}} }}
/> />
)}
{CoverEverywhere && spinningArt && (
<LunaNumberSetting <LunaNumberSetting
title="Spin Speed" title="Spin Speed"
desc="Adjust the rotation speed in seconds (10-120, default: 45) - Lower values = Faster rotation" desc="Adjust the rotation speed in seconds (10-120, default: 45) - Lower values = Faster rotation"
@@ -316,18 +701,21 @@ export const Settings = () => {
value={spinSpeed} value={spinSpeed}
onNumber={(value: number) => { onNumber={(value: number) => {
console.log("Spin Speed:", value); console.log("Spin Speed:", value);
setSpinSpeed((settings.spinSpeed = value)); settings.spinSpeed = value;
if ((window as any).updateRadiantLyricsGlobalBackground) { setSpinSpeed(value);
(window as any).updateRadiantLyricsGlobalBackground(); if (window.updateRadiantLyricsGlobalBackground) {
window.updateRadiantLyricsGlobalBackground();
} }
if ( if (
settings.settingsAffectNowPlaying && settings.settingsAffectNowPlaying &&
(window as any).updateRadiantLyricsNowPlayingBackground window.updateRadiantLyricsNowPlayingBackground
) { ) {
(window as any).updateRadiantLyricsNowPlayingBackground(); window.updateRadiantLyricsNowPlayingBackground();
} }
}} }}
/> />
)}
{CoverEverywhere && (
<AnySwitch <AnySwitch
title="Settings Affect Now Playing" title="Settings Affect Now Playing"
desc="Apply background settings to Now Playing view" desc="Apply background settings to Now Playing view"
@@ -337,15 +725,15 @@ export const Settings = () => {
"Settings Affect Now Playing:", "Settings Affect Now Playing:",
checked ? "enabled" : "disabled", checked ? "enabled" : "disabled",
); );
setSettingsAffectNowPlaying( settings.settingsAffectNowPlaying = checked;
(settings.settingsAffectNowPlaying = checked), setSettingsAffectNowPlaying(checked);
);
// Update Now Playing background immediately when setting changes // Update Now Playing background immediately when setting changes
if ((window as any).updateRadiantLyricsNowPlayingBackground) { if (window.updateRadiantLyricsNowPlayingBackground) {
(window as any).updateRadiantLyricsNowPlayingBackground(); window.updateRadiantLyricsNowPlayingBackground();
} }
}} }}
/> />
)}
</LunaSettings> </LunaSettings>
); );
}; };
@@ -0,0 +1,9 @@
/* Floating Rounded Player Bar from Obsidian <3 */
/* MARKER: Floating Player Bar CSS*/
[data-test="footer-player"] {
position: absolute !important;
backdrop-filter: blur(10px);
border: 1px solid var(--wave-color-opacity-contrast-fill-ultra-thin) !important;
}
+84 -3
View File
@@ -1,4 +1,4 @@
// Marker: Core Setup // MARKER: Core Setup
import { LunaUnload, Tracer, ftch } from "@luna/core"; import { LunaUnload, Tracer, ftch } from "@luna/core";
import { StyleTag, PlayState, observePromise, observe } from "@luna/lib"; import { StyleTag, PlayState, observePromise, observe } from "@luna/lib";
import { settings, Settings } from "./Settings"; import { settings, Settings } from "./Settings";
@@ -13,6 +13,7 @@ import baseStyles from "file://styles.css?minify";
import playerBarHidden from "file://player-bar-hidden.css?minify"; import playerBarHidden from "file://player-bar-hidden.css?minify";
import lyricsGlow from "file://lyrics-glow.css?minify"; import lyricsGlow from "file://lyrics-glow.css?minify";
import coverEverywhereCss from "file://cover-everywhere.css?minify"; import coverEverywhereCss from "file://cover-everywhere.css?minify";
import floatingPlayerBarCss from "file://floating-player-bar.css?minify";
// Core tracer and exports // Core tracer and exports
export const { trace } = Tracer("[Radiant Lyrics]"); export const { trace } = Tracer("[Radiant Lyrics]");
@@ -27,12 +28,78 @@ const lyricsStyleTag = new StyleTag("RadiantLyrics-lyrics", unloads);
const baseStyleTag = new StyleTag("RadiantLyrics-base", unloads); const baseStyleTag = new StyleTag("RadiantLyrics-base", unloads);
const playerBarStyleTag = new StyleTag("RadiantLyrics-player-bar", unloads); const playerBarStyleTag = new StyleTag("RadiantLyrics-player-bar", unloads);
const lyricsGlowStyleTag = new StyleTag("RadiantLyrics-lyrics-glow", unloads); const lyricsGlowStyleTag = new StyleTag("RadiantLyrics-lyrics-glow", unloads);
const floatingPlayerBarStyleTag = new StyleTag("RadiantLyrics-floating-player-bar", unloads);
// Apply lyrics glow styles if enabled // Apply lyrics glow styles if enabled
if (settings.lyricsGlowEnabled) { if (settings.lyricsGlowEnabled) {
lyricsGlowStyleTag.css = lyricsGlow; lyricsGlowStyleTag.css = lyricsGlow;
} }
// MARKER: Floating Player Bar
// Hex color to RGB
// (i'm deranged and love Hexadecimal)
const hexToRgb = (hex: string): { r: number; g: number; b: number } => {
let cleaned = (hex || "#000000").replace("#", "");
if (cleaned.length === 3) {
cleaned = cleaned[0] + cleaned[0] + cleaned[1] + cleaned[1] + cleaned[2] + cleaned[2];
}
if (cleaned.length !== 6) {
return { r: 0, g: 0, b: 0 };
}
return {
r: parseInt(cleaned.substring(0, 2), 16) || 0,
g: parseInt(cleaned.substring(2, 4), 16) || 0,
b: parseInt(cleaned.substring(4, 6), 16) || 0,
};
};
// Apply Settings to Floating Player Bar using inline styles because idk.. CSS is hard (Change my mind!)
const applyPlayerBarTintToElement = (): void => {
const footerPlayer = document.querySelector('[data-test="footer-player"]') as HTMLElement;
if (!footerPlayer) return;
// Always apply tint regardless of floating state
const alpha = settings.playerBarTint / 10;
const { r, g, b } = hexToRgb(settings.playerBarTintColor);
footerPlayer.style.setProperty("background-color", `rgba(${r}, ${g}, ${b}, ${alpha})`, "important");
if (settings.floatingPlayerBar) {
footerPlayer.style.setProperty("border-radius", `${settings.playerBarRadius}px`, "important");
const spacing = settings.playerBarSpacing;
footerPlayer.style.setProperty("bottom", `${spacing}px`, "important");
footerPlayer.style.setProperty("left", `${spacing}px`, "important");
footerPlayer.style.setProperty("width", `calc(100% - ${spacing * 2}px)`, "important");
} else {
footerPlayer.style.removeProperty("border-radius");
footerPlayer.style.removeProperty("bottom");
footerPlayer.style.removeProperty("left");
footerPlayer.style.removeProperty("width");
}
};
// Apply/update the floating player bar stylesheet + tint
const applyFloatingPlayerBar = (): void => {
if (settings.floatingPlayerBar) {
floatingPlayerBarStyleTag.css = floatingPlayerBarCss;
} else {
floatingPlayerBarStyleTag.remove();
}
applyPlayerBarTintToElement();
};
// Alias for settings callback
const updateRadiantLyricsPlayerBarTint = applyFloatingPlayerBar;
// Apply floating player bar styles if enabled
if (settings.floatingPlayerBar) {
floatingPlayerBarStyleTag.css = floatingPlayerBarCss;
}
// Apply Tint and Observe in case doesn't exist yet (ik this isnt the best way to do it but.. make a PR i dare ya!)
applyPlayerBarTintToElement();
observe<HTMLElement>(unloads, '[data-test="footer-player"]', () => {
applyPlayerBarTintToElement();
});
// Apply base styles always (contains global fixes and conditional UI hiding styles) // Apply base styles always (contains global fixes and conditional UI hiding styles)
baseStyleTag.css = baseStyles; baseStyleTag.css = baseStyles;
@@ -56,6 +123,9 @@ const updateRadiantLyricsStyles = function (): void {
playerBarStyleTag.remove(); playerBarStyleTag.remove();
} }
// Handle Floating Player Bar
applyFloatingPlayerBar();
// Update lyrics glow based on setting (Always apply if enabled, even when UI is hidden) // Update lyrics glow based on setting (Always apply if enabled, even when UI is hidden)
const lyricsContainer = document.querySelector('[class^="_lyricsContainer"]'); const lyricsContainer = document.querySelector('[class^="_lyricsContainer"]');
if (lyricsContainer) { if (lyricsContainer) {
@@ -96,7 +166,7 @@ const updateRadiantLyricsStyles = function (): void {
} }
}; };
// Marker: UI Visibility Control // MARKER: UI Visibility Control
// UI state shared across features // UI state shared across features
var isHidden = false; var isHidden = false;
let unhideButtonAutoFadeTimeout: number | null = null; let unhideButtonAutoFadeTimeout: number | null = null;
@@ -303,7 +373,7 @@ const createUnhideUIButton = function (): void {
}, 1500); }, 1500);
}; };
// Marker: Background Rendering // MARKER: Background Rendering
// Variable setup // Variable setup
let globalSpinningBgStyleTag: StyleTag | null = null; let globalSpinningBgStyleTag: StyleTag | null = null;
let globalBackgroundContainer: HTMLElement | null = null; let globalBackgroundContainer: HTMLElement | null = null;
@@ -790,6 +860,7 @@ const updateRadiantLyricsNowPlayingBackground = function (): void {
(window as any).updateRadiantLyricsNowPlayingBackground = (window as any).updateRadiantLyricsNowPlayingBackground =
updateRadiantLyricsNowPlayingBackground; updateRadiantLyricsNowPlayingBackground;
(window as any).updateRadiantLyricsTextGlow = updateRadiantLyricsTextGlow; (window as any).updateRadiantLyricsTextGlow = updateRadiantLyricsTextGlow;
(window as any).updateRadiantLyricsPlayerBarTint = updateRadiantLyricsPlayerBarTint;
const cleanUpDynamicArt = function (): void { const cleanUpDynamicArt = function (): void {
// Clean up cached Now Playing elements // Clean up cached Now Playing elements
@@ -861,6 +932,16 @@ updateCoverArtBackground(1);
unloads.add(() => { unloads.add(() => {
cleanUpDynamicArt(); cleanUpDynamicArt();
// Clean up floating player bar inline styles
const footerPlayer = document.querySelector('[data-test="footer-player"]') as HTMLElement;
if (footerPlayer) {
footerPlayer.style.removeProperty("background-color");
footerPlayer.style.removeProperty("border-radius");
footerPlayer.style.removeProperty("bottom");
footerPlayer.style.removeProperty("left");
footerPlayer.style.removeProperty("width");
}
// Clean up HideUI button auto-fade timeout // Clean up HideUI button auto-fade timeout
if (unhideButtonAutoFadeTimeout != null) { if (unhideButtonAutoFadeTimeout != null) {
window.clearTimeout(unhideButtonAutoFadeTimeout); window.clearTimeout(unhideButtonAutoFadeTimeout);