From c0255acb4c49cd38eef7e0b59b14788f436ae723 Mon Sep 17 00:00:00 2001 From: meowarex Date: Wed, 13 Aug 2025 20:25:20 +1000 Subject: [PATCH 1/4] Improved Settings --- plugins/colorama-lyrics-luna/src/Settings.tsx | 535 +++++++++++------- plugins/colorama-lyrics-luna/src/index.ts | 70 ++- plugins/colorama-lyrics-luna/src/styles.css | 19 +- 3 files changed, 407 insertions(+), 217 deletions(-) diff --git a/plugins/colorama-lyrics-luna/src/Settings.tsx b/plugins/colorama-lyrics-luna/src/Settings.tsx index 330b71f..0758c26 100644 --- a/plugins/colorama-lyrics-luna/src/Settings.tsx +++ b/plugins/colorama-lyrics-luna/src/Settings.tsx @@ -2,16 +2,20 @@ import { ReactiveStore } from "@luna/core"; import { LunaSettings, LunaNumberSetting, LunaSwitchSetting, LunaTextSetting } from "@luna/ui"; import React from "react"; -export type ColoramaMode = "single" | "gradient" | "auto-single" | "auto-gradient"; +export type ColoramaMode = "single" | "gradient" | "auto-single" | "auto-gradient" | "rainbow"; export const settings = await ReactiveStore.getPluginStorage("ColoramaLyrics", { enabled: true, mode: "single" as ColoramaMode, - // Store colors as ARGB hex (#AARRGGBB) - singleColor: "#FFFFFFFF", - gradientStart: "#FFFFFFFF", - gradientEnd: "#88AAFFFF", + // Store colors as RGB hex (#RRGGBB) and opacity separately (0-100) + singleColor: "#FFFFFF", + singleAlpha: 100, + gradientStart: "#FFFFFF", + gradientStartAlpha: 100, + gradientEnd: "#AAFFFF", + gradientEndAlpha: 100, gradientAngle: 0, + rainbowSpeed: 8, customColors: [] as string[], excludeInactive: false }); @@ -20,59 +24,67 @@ export const Settings = () => { const [enabled, setEnabled] = React.useState(settings.enabled); const [mode, setMode] = React.useState(settings.mode); const [singleColor, setSingleColor] = React.useState(settings.singleColor); + const [singleAlpha, setSingleAlpha] = React.useState(settings.singleAlpha ?? 100); const [gradientStart, setGradientStart] = React.useState(settings.gradientStart); + const [gradientStartAlpha, setGradientStartAlpha] = React.useState(settings.gradientStartAlpha ?? 100); const [gradientEnd, setGradientEnd] = React.useState(settings.gradientEnd); + const [gradientEndAlpha, setGradientEndAlpha] = React.useState(settings.gradientEndAlpha ?? 100); const [gradientAngle, setGradientAngle] = React.useState(settings.gradientAngle); + const [rainbowSpeed, setRainbowSpeed] = React.useState(settings.rainbowSpeed ?? 8); const [customInput, setCustomInput] = React.useState(settings.singleColor); const [customColors, setCustomColors] = React.useState(settings.customColors); const [showPicker, setShowPicker] = React.useState(false); const [isAnimatingIn, setIsAnimatingIn] = React.useState(false); const [shouldRender, setShouldRender] = React.useState(false); const [excludeInactive, setExcludeInactive] = React.useState(settings.excludeInactive); + const [activeEndpoint, setActiveEndpoint] = React.useState<'single' | 'start' | 'end'>('single'); + const AnySwitch = LunaSwitchSetting as unknown as React.ComponentType; - // Helpers for ARGB <-> components + // Helpers for HEX parsing and alpha extraction const clamp = (n: number, min: number, max: number) => Math.max(min, Math.min(max, n)); - const normalizeToARGB = (hex: string, fallback: string = "#FFFFFFFF"): string => { + const normalizeToRGB = (hex: string, fallback: string = "#FFFFFF"): string => { let v = hex.trim().toLowerCase(); if (!v.startsWith('#')) v = `#${v}`; // #rgb or #rgba -> expand if (/^#([0-9a-f]{3,4})$/.test(v)) { const m = v.slice(1); - const a = m.length === 4 ? m[3] : 'f'; const r = m[0]; const g = m[1]; const b = m[2]; - v = `#${a}${r}${g}${b}${r}${g}${b}${a}`; // temporary, will reformat below + // ignore alpha if provided (#rgba) + return `#${r}${r}${g}${g}${b}${b}`.toUpperCase(); + } + // #aarrggbb -> strip alpha + if (/^#([0-9a-f]{8})$/.test(v)) { + const rrggbb = v.slice(3); + return `#${rrggbb}`.toUpperCase(); } // #rrggbb - if (/^#([0-9a-f]{6})$/.test(v)) { - const m = v.slice(1); - const rrggbb = m; - const aa = 'ff'; - return `#${aa}${rrggbb}`.toUpperCase(); - } - // #aarrggbb - if (/^#([0-9a-f]{8})$/.test(v)) return v.toUpperCase(); + if (/^#([0-9a-f]{6})$/.test(v)) return v.toUpperCase(); return fallback; }; - const setAlphaOnARGB = (argb: string, alpha01: number): string => { - const a = clamp(Math.round(alpha01 * 255), 0, 255).toString(16).padStart(2, '0'); - const body = argb.replace('#', '').slice(2); - return (`#${a}${body}`).toUpperCase(); - }; - const getAlpha01 = (argb: string): number => { - const v = normalizeToARGB(argb); - const a = parseInt(v.slice(1, 3), 16); - return clamp(a / 255, 0, 1); + const extractAlphaPercent = (hex: string, fallbackPercent: number = 100): number => { + let v = hex.trim().toLowerCase(); + if (!v.startsWith('#')) v = `#${v}`; + if (/^#([0-9a-f]{4})$/.test(v)) { + const a = v[4]; + return Math.round((parseInt(a + a, 16) / 255) * 100); + } + if (/^#([0-9a-f]{8})$/.test(v)) { + const a = v.slice(1, 3); + return Math.round((parseInt(a, 16) / 255) * 100); + } + return fallbackPercent; }; const colorPresets = [ - "#FFFFFFFF", "#FF0000FF", "#00FF00FF", "#0000FFFF", "#FFFF00FF", "#FF00FFFF", "#00FFFFFF", - "#FF8800FF", "#8800FFFF", "#0088FFFF", "#88FF00FF", "#FF0088FF", "#00FF88FF", - "#444444FF", "#888888FF", "#CCCCCCFF", "#1DB954FF", "#E22134FF", "#1976D2FF" + "#FFFFFF", "#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FF00FF", "#00FFFF", + "#FF8800", "#8800FF", "#0088FF", "#88FF00", "#FF0088", "#00FF88", + "#444444", "#888888", "#CCCCCC", "#1DB954", "#E22134", "#1976D2" ]; - const openPicker = () => { + const openPicker = (endpoint: 'single' | 'start' | 'end' = 'single') => { + setActiveEndpoint(endpoint); setShowPicker(true); setShouldRender(true); setTimeout(() => setIsAnimatingIn(true), 10); @@ -85,16 +97,16 @@ export const Settings = () => { }, 200); }; - const argbColorRegex = /^#([0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3,4})$/i; + const hexColorRegex = /^#([0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3,4})$/i; const addCustomColor = () => { const trimmed = customInput.trim(); if ( - argbColorRegex.test(trimmed) && + hexColorRegex.test(trimmed) && !colorPresets.includes(trimmed) && - !customColors.includes(normalizeToARGB(trimmed)) + !customColors.includes(normalizeToRGB(trimmed)) ) { - const updated = [...customColors, normalizeToARGB(trimmed)]; + const updated = [...customColors, normalizeToRGB(trimmed)]; setCustomColors(updated); settings.customColors = updated; } @@ -115,12 +127,10 @@ export const Settings = () => { return ( - {/* Mode selection via dropdown */} -
-
-
Mode
-
Choose how lyrics are colored
-
+ {/* Mode selection via dropdown (aligned right) */} +
+
Mode
+
Choose how lyrics are colored
@@ -148,101 +161,71 @@ export const Settings = () => {
Lyrics Color
-
Solid color (HEX/ARGB HEX)
+
Solid color (configure inside picker)
-
- { - const next = setAlphaOnARGB(normalizeToARGB(singleColor), value / 100); - setSingleColor((settings.singleColor = next)); - if (customInput) setCustomInput(next); - requestApply(); - }} - /> -
+ - {/* Gradient controls */} + {/* Gradient controls (triggers only) */}
Gradient
-
Pick start/end and angle
+
Pick start/end and angle (inside picker)
- { - const next = setAlphaOnARGB(normalizeToARGB(gradientStart), value / 100); - setGradientStart((settings.gradientStart = next)); - requestApply(); - }} - /> - { - const next = setAlphaOnARGB(normalizeToARGB(gradientEnd), value / 100); - setGradientEnd((settings.gradientEnd = next)); - requestApply(); - }} - /> - { - setGradientAngle((settings.gradientAngle = value)); - requestApply(); - }} - />
+ {/* Auto gradient controls (open picker for angle) */} +
+
+
Auto Gradient
+
Configure angle inside the picker
+
+ +
+ + {/* Rainbow controls removed: mode exists but has no UI */} + {/* Modal for picking and managing colors (reused) */} {shouldRender && ( <> @@ -281,112 +264,254 @@ export const Settings = () => { transition: "all 0.2s ease" }} > -
Choose Color (ARGB HEX)
-
- {allColors.map((color, index) => ( - + +
+ )} + {mode !== 'auto-gradient' && ( +
+ {allColors.map((color, index) => ( +
+ )} + {mode !== 'auto-gradient' && ( +
+
Custom Hex (#RRGGBB)
+
+ setCustomInput(e.target.value)} + onKeyDown={(e) => { + if (e.key === 'Enter') { + const trimmed = customInput.trim(); + if (hexColorRegex.test(trimmed)) { + if (mode === "single") { + const next = normalizeToRGB(trimmed); + setSingleColor((settings.singleColor = next)); + setCustomInput(next); + } else if (mode === "gradient") { + const norm = normalizeToRGB(trimmed); + if (activeEndpoint === 'end') { + setGradientEnd((settings.gradientEnd = norm)); + } else { + setGradientStart((settings.gradientStart = norm)); + } + setCustomInput(norm); + } + requestApply(); + } + addCustomColor(); + } + }} + placeholder="#RRGGBB" + style={{ + flex: 1, + padding: "8px 12px", + borderRadius: 6, + border: "1px solid rgba(255,255,255,0.2)", + background: "rgba(255,255,255,0.1)", + color: "#fff", + fontSize: 14, + fontFamily: "monospace", + boxSizing: "border-box" + }} + /> + + }} + style={{ + width: 32, + height: 32, + borderRadius: 6, + border: "1px solid rgba(255,255,255,0.3)", + background: "rgba(255,255,255,0.15)", + color: "#fff", + cursor: "pointer", + fontSize: 16, + display: "flex", + alignItems: "center", + justifyContent: "center", + transition: "all 0.2s ease" + }} + > + + + +
-
+ )} + {/* Sliders inside picker based on mode */} + {mode === 'single' && ( +
+
Alpha
+ { + const value = Number(e.target.value); + setSingleAlpha((settings.singleAlpha = value)); + requestApply(); + }} + style={{ width: '100%' }} + /> +
+ )} + + {mode === 'gradient' && ( +
+
+
+
+
Start Alpha
+
+ { + const value = Number(e.target.value); + setGradientStartAlpha((settings.gradientStartAlpha = value)); + requestApply(); + }} + style={{ width: '100%' }} + /> +
+
+
+
+
End Alpha
+
+ { + const value = Number(e.target.value); + setGradientEndAlpha((settings.gradientEndAlpha = value)); + requestApply(); + }} + style={{ width: '100%' }} + /> +
+
+
+
Angle
+
{gradientAngle}°
+
+ { + const value = Number(e.target.value); + setGradientAngle((settings.gradientAngle = value)); + requestApply(); + }} + style={{ width: '100%' }} + /> +
+
+ )} + + {mode === 'auto-gradient' && ( +
+
+
Angle
+
{gradientAngle}°
+
+ { + const value = Number(e.target.value); + setGradientAngle((settings.gradientAngle = value)); + requestApply(); + }} + style={{ width: '100%' }} + /> +
+ )} +
)} - hookRadiantUpdates(), 0); +// Observe active lyric span changes and restart rainbow animation to avoid freezes +// Rainbow mode disabled: no lyrics observer needed + diff --git a/plugins/colorama-lyrics-luna/src/styles.css b/plugins/colorama-lyrics-luna/src/styles.css index 999bf25..13a023b 100644 --- a/plugins/colorama-lyrics-luna/src/styles.css +++ b/plugins/colorama-lyrics-luna/src/styles.css @@ -32,6 +32,9 @@ -webkit-text-fill-color: transparent !important; } +/* Ensure active line keeps rainbow in only-active mode */ +/* Only-active: apply container class only on the active line via JS */ + /* Slight emphasis on current line (uniform to single mode) */ .colorama-gradient [class*="_lyricsText"] > div > span[data-current="true"], .colorama-gradient [class^="_lyricsContainer"] > div > div > span[data-current="true"] { @@ -69,12 +72,24 @@ /* Only color active line mode */ body.colorama-only-active.colorama-single [class*="_lyricsText"] > div > span:not([data-current="true"]), body.colorama-only-active.colorama-gradient [class*="_lyricsText"] > div > span:not([data-current="true"]) { - /* Reset non-active lines to default */ - color: inherit !important; + /* Match Radiant inactive styling */ + color: rgba(128, 128, 128, 0.4) !important; background: none !important; -webkit-background-clip: initial !important; background-clip: initial !important; -webkit-text-fill-color: initial !important; + text-shadow: initial !important; +} + +/* In only-active mode, keep TIDAL defaults even on hover for inactive lines */ +body.colorama-only-active.colorama-single [class*="_lyricsText"] > div > span:not([data-current="true"]):hover, +body.colorama-only-active.colorama-gradient [class*="_lyricsText"] > div > span:not([data-current="true"]):hover { + color: lightgray !important; + background: none !important; + -webkit-background-clip: initial !important; + background-clip: initial !important; + -webkit-text-fill-color: initial !important; + text-shadow: initial !important; } From 40ed89dd346bfa54c87431aea2c2db2c700194c0 Mon Sep 17 00:00:00 2001 From: meowarex Date: Wed, 13 Aug 2025 21:08:30 +1000 Subject: [PATCH 2/4] Updated Settings --- plugins/colorama-lyrics-luna/src/Settings.tsx | 86 +++++++++---------- plugins/colorama-lyrics-luna/src/index.ts | 24 +++--- plugins/colorama-lyrics-luna/src/styles.css | 1 - 3 files changed, 51 insertions(+), 60 deletions(-) diff --git a/plugins/colorama-lyrics-luna/src/Settings.tsx b/plugins/colorama-lyrics-luna/src/Settings.tsx index 0758c26..d6139a1 100644 --- a/plugins/colorama-lyrics-luna/src/Settings.tsx +++ b/plugins/colorama-lyrics-luna/src/Settings.tsx @@ -2,7 +2,7 @@ import { ReactiveStore } from "@luna/core"; import { LunaSettings, LunaNumberSetting, LunaSwitchSetting, LunaTextSetting } from "@luna/ui"; import React from "react"; -export type ColoramaMode = "single" | "gradient" | "auto-single" | "auto-gradient" | "rainbow"; +export type ColoramaMode = "single" | "gradient-experimental" | "cover" | "cover-gradient"; export const settings = await ReactiveStore.getPluginStorage("ColoramaLyrics", { enabled: true, @@ -15,7 +15,6 @@ export const settings = await ReactiveStore.getPluginStorage("ColoramaLyrics", { gradientEnd: "#AAFFFF", gradientEndAlpha: 100, gradientAngle: 0, - rainbowSpeed: 8, customColors: [] as string[], excludeInactive: false }); @@ -30,7 +29,6 @@ export const Settings = () => { const [gradientEnd, setGradientEnd] = React.useState(settings.gradientEnd); const [gradientEndAlpha, setGradientEndAlpha] = React.useState(settings.gradientEndAlpha ?? 100); const [gradientAngle, setGradientAngle] = React.useState(settings.gradientAngle); - const [rainbowSpeed, setRainbowSpeed] = React.useState(settings.rainbowSpeed ?? 8); const [customInput, setCustomInput] = React.useState(settings.singleColor); const [customColors, setCustomColors] = React.useState(settings.customColors); const [showPicker, setShowPicker] = React.useState(false); @@ -129,8 +127,10 @@ export const Settings = () => { {/* Mode selection via dropdown (aligned right) */}
-
Mode
-
Choose how lyrics are colored
+
+
Mode
+
Choose how lyrics are colored
+
@@ -161,7 +160,7 @@ export const Settings = () => {
Lyrics Color
-
Solid color (configure inside picker)
+
Set lyrics color
- {/* Gradient controls (triggers only) */} -
-
Gradient
-
Pick start/end and angle (inside picker)
-
-
- {/* Auto gradient controls (open picker for angle) */} -
+ {/* Cover gradient controls (open picker for angle) */} +
-
Auto Gradient
-
Configure angle inside the picker
+
Cover (Gradient) - Experimental
+
Set angle
- {/* Rainbow controls removed: mode exists but has no UI */} + {/* Rainbow mode removed */} {/* Modal for picking and managing colors (reused) */} {shouldRender && ( @@ -267,7 +263,7 @@ export const Settings = () => {
{mode === 'single' ? 'Single Color' : 'Gradient Colors'}
- {mode === 'gradient' && ( + {mode === 'gradient-experimental' && (
Editing
)} - {mode !== 'auto-gradient' && ( + {mode !== 'cover-gradient' && (
{allColors.map((color, index) => (
)} - {mode !== 'auto-gradient' && ( + {mode !== 'cover-gradient' && (
Custom Hex (#RRGGBB)
@@ -343,7 +339,7 @@ export const Settings = () => { const next = normalizeToRGB(trimmed); setSingleColor((settings.singleColor = next)); setCustomInput(next); - } else if (mode === "gradient") { + } else if (mode === "gradient-experimental") { const norm = normalizeToRGB(trimmed); if (activeEndpoint === 'end') { setGradientEnd((settings.gradientEnd = norm)); @@ -376,7 +372,7 @@ export const Settings = () => { if (hexColorRegex.test(trimmed)) { if (mode === "single") { setSingleColor((settings.singleColor = normalizeToRGB(trimmed))); - } else if (mode === "gradient") { + } else if (mode === "gradient-experimental") { const norm = normalizeToRGB(trimmed); if (activeEndpoint === 'end') { setGradientEnd((settings.gradientEnd = norm)); @@ -428,7 +424,7 @@ export const Settings = () => {
)} - {mode === 'gradient' && ( + {mode === 'gradient-experimental' && (
@@ -490,7 +486,7 @@ export const Settings = () => {
)} - {mode === 'auto-gradient' && ( + {mode === 'cover-gradient' && (
Angle
@@ -531,7 +527,7 @@ export const Settings = () => { )} { diff --git a/plugins/colorama-lyrics-luna/src/index.ts b/plugins/colorama-lyrics-luna/src/index.ts index 285197b..0fa3c43 100644 --- a/plugins/colorama-lyrics-luna/src/index.ts +++ b/plugins/colorama-lyrics-luna/src/index.ts @@ -124,10 +124,10 @@ function applyGradient(start: string, end: string, angle: number) { } function resetModeClasses(): void { - document.body.classList.remove('colorama-single', 'colorama-gradient', 'colorama-rainbow'); + document.body.classList.remove('colorama-single', 'colorama-gradient'); } -async function applyAutoColors(gradient: boolean) { +async function applyCoverColors(gradient: boolean) { const img = await getCoverArtElement(); if (!img) return; const colors = getDominantColorsFromImage(img, gradient ? 2 : 1); @@ -143,7 +143,7 @@ async function applyAutoColors(gradient: boolean) { function applyColoramaLyrics(): void { if (!settings.enabled) { - document.body.classList.remove('colorama-single', 'colorama-gradient', 'colorama-rainbow'); + document.body.classList.remove('colorama-single', 'colorama-gradient'); return; } @@ -158,17 +158,14 @@ function applyColoramaLyrics(): void { case "single": applySingleColor(settings.singleColor); break; - case "gradient": + case "gradient-experimental": applyGradient(settings.gradientStart, settings.gradientEnd, settings.gradientAngle); break; - case "rainbow": - // no-op: rainbow mode disabled + case "cover": + applyCoverColors(false); break; - case "auto-single": - applyAutoColors(false); - break; - case "auto-gradient": - applyAutoColors(true); + case "cover-gradient": + applyCoverColors(true); break; } } @@ -182,7 +179,7 @@ function observeTrackChanges(): void { const currentTrackId = PlayState.playbackContext?.actualProductId; if (currentTrackId && currentTrackId !== lastTrackId) { lastTrackId = currentTrackId; - if (settings.mode.startsWith("auto")) { + if (settings.mode === 'cover' || settings.mode === 'cover-gradient') { setTimeout(() => applyColoramaLyrics(), 200); } } @@ -220,7 +217,6 @@ function hookRadiantUpdates(): void { setTimeout(() => hookRadiantUpdates(), 0); -// Observe active lyric span changes and restart rainbow animation to avoid freezes -// Rainbow mode disabled: no lyrics observer needed +// Rainbow mode removed diff --git a/plugins/colorama-lyrics-luna/src/styles.css b/plugins/colorama-lyrics-luna/src/styles.css index 13a023b..494acf1 100644 --- a/plugins/colorama-lyrics-luna/src/styles.css +++ b/plugins/colorama-lyrics-luna/src/styles.css @@ -32,7 +32,6 @@ -webkit-text-fill-color: transparent !important; } -/* Ensure active line keeps rainbow in only-active mode */ /* Only-active: apply container class only on the active line via JS */ /* Slight emphasis on current line (uniform to single mode) */ From 0b9c27eaaf2cc529d2f8ce8965ba06ff51664f8b Mon Sep 17 00:00:00 2001 From: meowarex Date: Wed, 13 Aug 2025 21:14:32 +1000 Subject: [PATCH 3/4] Cleanup --- plugins/colorama-lyrics-luna/src/Settings.tsx | 20 ++----------------- plugins/colorama-lyrics-luna/src/index.ts | 9 +++------ 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/plugins/colorama-lyrics-luna/src/Settings.tsx b/plugins/colorama-lyrics-luna/src/Settings.tsx index d6139a1..7692f90 100644 --- a/plugins/colorama-lyrics-luna/src/Settings.tsx +++ b/plugins/colorama-lyrics-luna/src/Settings.tsx @@ -1,5 +1,5 @@ import { ReactiveStore } from "@luna/core"; -import { LunaSettings, LunaNumberSetting, LunaSwitchSetting, LunaTextSetting } from "@luna/ui"; +import { LunaSettings, LunaSwitchSetting } from "@luna/ui"; import React from "react"; export type ColoramaMode = "single" | "gradient-experimental" | "cover" | "cover-gradient"; @@ -38,8 +38,7 @@ export const Settings = () => { const [activeEndpoint, setActiveEndpoint] = React.useState<'single' | 'start' | 'end'>('single'); const AnySwitch = LunaSwitchSetting as unknown as React.ComponentType; - // Helpers for HEX parsing and alpha extraction - const clamp = (n: number, min: number, max: number) => Math.max(min, Math.min(max, n)); + // Helper for HEX normalization const normalizeToRGB = (hex: string, fallback: string = "#FFFFFF"): string => { let v = hex.trim().toLowerCase(); if (!v.startsWith('#')) v = `#${v}`; @@ -61,19 +60,6 @@ export const Settings = () => { if (/^#([0-9a-f]{6})$/.test(v)) return v.toUpperCase(); return fallback; }; - const extractAlphaPercent = (hex: string, fallbackPercent: number = 100): number => { - let v = hex.trim().toLowerCase(); - if (!v.startsWith('#')) v = `#${v}`; - if (/^#([0-9a-f]{4})$/.test(v)) { - const a = v[4]; - return Math.round((parseInt(a + a, 16) / 255) * 100); - } - if (/^#([0-9a-f]{8})$/.test(v)) { - const a = v.slice(1, 3); - return Math.round((parseInt(a, 16) / 255) * 100); - } - return fallbackPercent; - }; const colorPresets = [ "#FFFFFF", "#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FF00FF", "#00FFFF", @@ -220,8 +206,6 @@ export const Settings = () => {
- {/* Rainbow mode removed */} - {/* Modal for picking and managing colors (reused) */} {shouldRender && ( <> diff --git a/plugins/colorama-lyrics-luna/src/index.ts b/plugins/colorama-lyrics-luna/src/index.ts index 0fa3c43..23b82cf 100644 --- a/plugins/colorama-lyrics-luna/src/index.ts +++ b/plugins/colorama-lyrics-luna/src/index.ts @@ -1,4 +1,3 @@ -// NOTE: definition duplicated earlier accidentally; keep this single definition below import { LunaUnload, Tracer } from "@luna/core"; import { StyleTag, PlayState } from "@luna/lib"; import { settings, Settings } from "./Settings"; @@ -10,7 +9,7 @@ export { Settings }; export const unloads = new Set(); -const styleTag = new StyleTag("ColoramaLyrics", unloads, styles); +new StyleTag("ColoramaLyrics", unloads, styles); // Simple dominant color extraction from current cover art async function getCoverArtElement(): Promise { @@ -64,7 +63,7 @@ function getDominantColorsFromImage(img: HTMLImageElement, count: number = 2): s } } -// Utilities to build rgba() from hex + alpha percentage +// build rgba() from hex + alpha percentage function hexToRgb(hex: string): { r: number; g: number; b: number } | null { let v = hex.trim(); if (!v.startsWith('#')) v = `#${v}`; @@ -193,7 +192,7 @@ function observeTrackChanges(): void { setTimeout(() => applyColoramaLyrics(), 200); observeTrackChanges(); -// Ensure compatibility: re-apply after Radiant updates its styles/backgrounds +// for some reason, re-apply after Radiant updates its styles/backgrounds function hookRadiantUpdates(): void { const w = window as any; const wrap = (name: string) => { @@ -217,6 +216,4 @@ function hookRadiantUpdates(): void { setTimeout(() => hookRadiantUpdates(), 0); -// Rainbow mode removed - From 82dfb39ff52382f1bebd683f2eac33a039b266d1 Mon Sep 17 00:00:00 2001 From: meowarex Date: Wed, 13 Aug 2025 21:32:06 +1000 Subject: [PATCH 4/4] Improved Settings + Labeling --- plugins/colorama-lyrics-luna/src/Settings.tsx | 52 ++++++++----------- plugins/colorama-lyrics-luna/src/index.ts | 2 + 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/plugins/colorama-lyrics-luna/src/Settings.tsx b/plugins/colorama-lyrics-luna/src/Settings.tsx index 7692f90..eb01980 100644 --- a/plugins/colorama-lyrics-luna/src/Settings.tsx +++ b/plugins/colorama-lyrics-luna/src/Settings.tsx @@ -83,6 +83,25 @@ export const Settings = () => { const hexColorRegex = /^#([0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3,4})$/i; + const applyCustomInputColor = (raw: string, updateInput: boolean): void => { + const trimmed = raw.trim(); + if (!hexColorRegex.test(trimmed)) return; + if (mode === "single") { + const next = normalizeToRGB(trimmed); + setSingleColor((settings.singleColor = next)); + if (updateInput) setCustomInput(next); + } else if (mode === "gradient-experimental") { + const norm = normalizeToRGB(trimmed); + if (activeEndpoint === 'end') { + setGradientEnd((settings.gradientEnd = norm)); + } else { + setGradientStart((settings.gradientStart = norm)); + } + if (updateInput) setCustomInput(norm); + } + requestApply(); + }; + const addCustomColor = () => { const trimmed = customInput.trim(); if ( @@ -317,23 +336,7 @@ export const Settings = () => { onChange={(e) => setCustomInput(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') { - const trimmed = customInput.trim(); - if (hexColorRegex.test(trimmed)) { - if (mode === "single") { - const next = normalizeToRGB(trimmed); - setSingleColor((settings.singleColor = next)); - setCustomInput(next); - } else if (mode === "gradient-experimental") { - const norm = normalizeToRGB(trimmed); - if (activeEndpoint === 'end') { - setGradientEnd((settings.gradientEnd = norm)); - } else { - setGradientStart((settings.gradientStart = norm)); - } - setCustomInput(norm); - } - requestApply(); - } + applyCustomInputColor(customInput, true); addCustomColor(); } }} @@ -352,20 +355,7 @@ export const Settings = () => { />