mirror of
https://github.com/meowarex/TidaLuna-Plugins.git
synced 2026-06-18 03:43:10 +10:00
Updated Settings
This commit is contained in:
@@ -2,7 +2,7 @@ import { ReactiveStore } from "@luna/core";
|
|||||||
import { LunaSettings, LunaNumberSetting, LunaSwitchSetting, LunaTextSetting } from "@luna/ui";
|
import { LunaSettings, LunaNumberSetting, LunaSwitchSetting, LunaTextSetting } from "@luna/ui";
|
||||||
import React from "react";
|
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", {
|
export const settings = await ReactiveStore.getPluginStorage("ColoramaLyrics", {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -15,7 +15,6 @@ export const settings = await ReactiveStore.getPluginStorage("ColoramaLyrics", {
|
|||||||
gradientEnd: "#AAFFFF",
|
gradientEnd: "#AAFFFF",
|
||||||
gradientEndAlpha: 100,
|
gradientEndAlpha: 100,
|
||||||
gradientAngle: 0,
|
gradientAngle: 0,
|
||||||
rainbowSpeed: 8,
|
|
||||||
customColors: [] as string[],
|
customColors: [] as string[],
|
||||||
excludeInactive: false
|
excludeInactive: false
|
||||||
});
|
});
|
||||||
@@ -30,7 +29,6 @@ export const Settings = () => {
|
|||||||
const [gradientEnd, setGradientEnd] = React.useState(settings.gradientEnd);
|
const [gradientEnd, setGradientEnd] = React.useState(settings.gradientEnd);
|
||||||
const [gradientEndAlpha, setGradientEndAlpha] = React.useState<number>(settings.gradientEndAlpha ?? 100);
|
const [gradientEndAlpha, setGradientEndAlpha] = React.useState<number>(settings.gradientEndAlpha ?? 100);
|
||||||
const [gradientAngle, setGradientAngle] = React.useState(settings.gradientAngle);
|
const [gradientAngle, setGradientAngle] = React.useState(settings.gradientAngle);
|
||||||
const [rainbowSpeed, setRainbowSpeed] = React.useState<number>(settings.rainbowSpeed ?? 8);
|
|
||||||
const [customInput, setCustomInput] = React.useState(settings.singleColor);
|
const [customInput, setCustomInput] = React.useState(settings.singleColor);
|
||||||
const [customColors, setCustomColors] = React.useState(settings.customColors);
|
const [customColors, setCustomColors] = React.useState(settings.customColors);
|
||||||
const [showPicker, setShowPicker] = React.useState(false);
|
const [showPicker, setShowPicker] = React.useState(false);
|
||||||
@@ -129,8 +127,10 @@ export const Settings = () => {
|
|||||||
|
|
||||||
{/* Mode selection via dropdown (aligned right) */}
|
{/* Mode selection via dropdown (aligned right) */}
|
||||||
<div style={{ padding: "8px 0", display: "flex", alignItems: "center", gap: 12 }}>
|
<div style={{ padding: "8px 0", display: "flex", alignItems: "center", gap: 12 }}>
|
||||||
<div style={{ fontWeight: "normal", fontSize: "1.075rem" }}>Mode</div>
|
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||||
<div style={{ opacity: 0.7, fontSize: 14 }}>Choose how lyrics are colored</div>
|
<div style={{ fontWeight: "normal", fontSize: "1.075rem" }}>Mode</div>
|
||||||
|
<div style={{ opacity: 0.7, fontSize: 14 }}>Choose how lyrics are colored</div>
|
||||||
|
</div>
|
||||||
<select
|
<select
|
||||||
value={mode}
|
value={mode}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
@@ -150,10 +150,9 @@ export const Settings = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<option value="single" style={{ color: '#000', background: '#fff' }}>Single</option>
|
<option value="single" style={{ color: '#000', background: '#fff' }}>Single</option>
|
||||||
<option value="gradient" style={{ color: '#000', background: '#fff' }}>Gradient</option>
|
<option value="gradient-experimental" style={{ color: '#000', background: '#fff' }}>Gradient - Experimental</option>
|
||||||
<option value="auto-single" style={{ color: '#000', background: '#fff' }}>Auto (Cover)</option>
|
<option value="cover" style={{ color: '#000', background: '#fff' }}>Cover - Experimental</option>
|
||||||
<option value="auto-gradient" style={{ color: '#000', background: '#fff' }}>Auto Gradient</option>
|
<option value="cover-gradient" style={{ color: '#000', background: '#fff' }}>Cover (Gradient) - Experimental</option>
|
||||||
<option value="rainbow" style={{ color: '#000', background: '#fff' }}>Rainbow</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -161,7 +160,7 @@ export const Settings = () => {
|
|||||||
<div style={{ padding: "8px 0", display: mode === "single" ? "flex" : "none", justifyContent: "space-between", alignItems: "center" }}>
|
<div style={{ padding: "8px 0", display: mode === "single" ? "flex" : "none", justifyContent: "space-between", alignItems: "center" }}>
|
||||||
<div>
|
<div>
|
||||||
<div style={{ fontWeight: "normal", fontSize: "1.075rem", marginBottom: 4 }}>Lyrics Color</div>
|
<div style={{ fontWeight: "normal", fontSize: "1.075rem", marginBottom: 4 }}>Lyrics Color</div>
|
||||||
<div style={{ opacity: 0.7, fontSize: 14 }}>Solid color (configure inside picker)</div>
|
<div style={{ opacity: 0.7, fontSize: 14 }}>Set lyrics color</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", gap: 8, alignItems: "center", position: "relative" }}>
|
<div style={{ display: "flex", gap: 8, alignItems: "center", position: "relative" }}>
|
||||||
<button
|
<button
|
||||||
@@ -179,35 +178,32 @@ export const Settings = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{/* Gradient controls (triggers only) */}
|
{/* Gradient controls (open picker) */}
|
||||||
<div style={{ padding: "8px 0", display: mode === "gradient" ? "block" : "none" }}>
|
<div style={{ padding: "8px 0", display: mode === "gradient-experimental" ? "flex" : "none", justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
<div style={{ fontWeight: "normal", fontSize: "1.075rem", marginBottom: 4 }}>Gradient</div>
|
<div>
|
||||||
<div style={{ opacity: 0.7, fontSize: 14, marginBottom: 8 }}>Pick start/end and angle (inside picker)</div>
|
<div style={{ fontWeight: "normal", fontSize: "1.075rem", marginBottom: 4 }}>Gradient (Experimental)</div>
|
||||||
<div style={{ display: "flex", gap: 12, alignItems: "center" }}>
|
<div style={{ opacity: 0.7, fontSize: 14 }}>Set colors & angle</div>
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
setCustomInput(gradientStart);
|
|
||||||
openPicker('start');
|
|
||||||
}}
|
|
||||||
title="Start Color"
|
|
||||||
style={{ width: 32, height: 32, border: "1px solid rgba(255,255,255,0.15)", borderRadius: 6, background: normalizeToRGB(gradientStart) }}
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
setCustomInput(gradientEnd);
|
|
||||||
openPicker('end');
|
|
||||||
}}
|
|
||||||
title="End Color"
|
|
||||||
style={{ width: 32, height: 32, border: "1px solid rgba(255,255,255,0.15)", borderRadius: 6, background: normalizeToRGB(gradientEnd) }}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => { setCustomInput(gradientStart); openPicker('start'); }}
|
||||||
|
style={{
|
||||||
|
padding: '8px 12px',
|
||||||
|
borderRadius: 8,
|
||||||
|
border: '1px solid rgba(255,255,255,0.2)',
|
||||||
|
background: 'rgba(255,255,255,0.08)',
|
||||||
|
color: '#fff',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Configure
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Auto gradient controls (open picker for angle) */}
|
{/* Cover gradient controls (open picker for angle) */}
|
||||||
<div style={{ padding: "8px 0", display: mode === "auto-gradient" ? "flex" : "none", justifyContent: 'space-between', alignItems: 'center' }}>
|
<div style={{ padding: "8px 0", display: mode === "cover-gradient" ? "flex" : "none", justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
<div>
|
<div>
|
||||||
<div style={{ fontWeight: "normal", fontSize: "1.075rem", marginBottom: 4 }}>Auto Gradient</div>
|
<div style={{ fontWeight: "normal", fontSize: "1.075rem", marginBottom: 4 }}>Cover (Gradient) - Experimental</div>
|
||||||
<div style={{ opacity: 0.7, fontSize: 14 }}>Configure angle inside the picker</div>
|
<div style={{ opacity: 0.7, fontSize: 14 }}>Set angle</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={() => openPicker('start')}
|
onClick={() => openPicker('start')}
|
||||||
@@ -224,7 +220,7 @@ export const Settings = () => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Rainbow controls removed: mode exists but has no UI */}
|
{/* Rainbow mode removed */}
|
||||||
|
|
||||||
{/* Modal for picking and managing colors (reused) */}
|
{/* Modal for picking and managing colors (reused) */}
|
||||||
{shouldRender && (
|
{shouldRender && (
|
||||||
@@ -267,7 +263,7 @@ export const Settings = () => {
|
|||||||
<div style={{ marginBottom: 12, color: "#fff", fontWeight: "bold", fontSize: 14 }}>
|
<div style={{ marginBottom: 12, color: "#fff", fontWeight: "bold", fontSize: 14 }}>
|
||||||
{mode === 'single' ? 'Single Color' : 'Gradient Colors'}
|
{mode === 'single' ? 'Single Color' : 'Gradient Colors'}
|
||||||
</div>
|
</div>
|
||||||
{mode === 'gradient' && (
|
{mode === 'gradient-experimental' && (
|
||||||
<div style={{ display: 'flex', gap: 8, alignItems: 'center', marginBottom: 12 }}>
|
<div style={{ display: 'flex', gap: 8, alignItems: 'center', marginBottom: 12 }}>
|
||||||
<div style={{ color: 'rgba(255,255,255,0.7)', fontSize: 12 }}>Editing</div>
|
<div style={{ color: 'rgba(255,255,255,0.7)', fontSize: 12 }}>Editing</div>
|
||||||
<button
|
<button
|
||||||
@@ -296,7 +292,7 @@ export const Settings = () => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{mode !== 'auto-gradient' && (
|
{mode !== 'cover-gradient' && (
|
||||||
<div style={{ display: "grid", gridTemplateColumns: "repeat(7, 1fr)", gap: 8, marginBottom: 16 }}>
|
<div style={{ display: "grid", gridTemplateColumns: "repeat(7, 1fr)", gap: 8, marginBottom: 16 }}>
|
||||||
{allColors.map((color, index) => (
|
{allColors.map((color, index) => (
|
||||||
<button
|
<button
|
||||||
@@ -305,7 +301,7 @@ export const Settings = () => {
|
|||||||
if (mode === "single") {
|
if (mode === "single") {
|
||||||
const next = normalizeToRGB(color);
|
const next = normalizeToRGB(color);
|
||||||
setSingleColor((settings.singleColor = next));
|
setSingleColor((settings.singleColor = next));
|
||||||
} else if (mode === "gradient") {
|
} else if (mode === "gradient-experimental") {
|
||||||
if (activeEndpoint === 'end') {
|
if (activeEndpoint === 'end') {
|
||||||
setGradientEnd((settings.gradientEnd = normalizeToRGB(color)));
|
setGradientEnd((settings.gradientEnd = normalizeToRGB(color)));
|
||||||
} else {
|
} else {
|
||||||
@@ -327,7 +323,7 @@ export const Settings = () => {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{mode !== 'auto-gradient' && (
|
{mode !== 'cover-gradient' && (
|
||||||
<div style={{ marginBottom: 12 }}>
|
<div style={{ marginBottom: 12 }}>
|
||||||
<div style={{ color: "rgba(255,255,255,0.7)", fontSize: 12, marginBottom: 6 }}>Custom Hex (#RRGGBB)</div>
|
<div style={{ color: "rgba(255,255,255,0.7)", fontSize: 12, marginBottom: 6 }}>Custom Hex (#RRGGBB)</div>
|
||||||
<div style={{ display: "flex", gap: 8, alignItems: "center" }}>
|
<div style={{ display: "flex", gap: 8, alignItems: "center" }}>
|
||||||
@@ -343,7 +339,7 @@ export const Settings = () => {
|
|||||||
const next = normalizeToRGB(trimmed);
|
const next = normalizeToRGB(trimmed);
|
||||||
setSingleColor((settings.singleColor = next));
|
setSingleColor((settings.singleColor = next));
|
||||||
setCustomInput(next);
|
setCustomInput(next);
|
||||||
} else if (mode === "gradient") {
|
} else if (mode === "gradient-experimental") {
|
||||||
const norm = normalizeToRGB(trimmed);
|
const norm = normalizeToRGB(trimmed);
|
||||||
if (activeEndpoint === 'end') {
|
if (activeEndpoint === 'end') {
|
||||||
setGradientEnd((settings.gradientEnd = norm));
|
setGradientEnd((settings.gradientEnd = norm));
|
||||||
@@ -376,7 +372,7 @@ export const Settings = () => {
|
|||||||
if (hexColorRegex.test(trimmed)) {
|
if (hexColorRegex.test(trimmed)) {
|
||||||
if (mode === "single") {
|
if (mode === "single") {
|
||||||
setSingleColor((settings.singleColor = normalizeToRGB(trimmed)));
|
setSingleColor((settings.singleColor = normalizeToRGB(trimmed)));
|
||||||
} else if (mode === "gradient") {
|
} else if (mode === "gradient-experimental") {
|
||||||
const norm = normalizeToRGB(trimmed);
|
const norm = normalizeToRGB(trimmed);
|
||||||
if (activeEndpoint === 'end') {
|
if (activeEndpoint === 'end') {
|
||||||
setGradientEnd((settings.gradientEnd = norm));
|
setGradientEnd((settings.gradientEnd = norm));
|
||||||
@@ -428,7 +424,7 @@ export const Settings = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{mode === 'gradient' && (
|
{mode === 'gradient-experimental' && (
|
||||||
<div style={{ marginBottom: 16, display: 'grid', gap: 16 }}>
|
<div style={{ marginBottom: 16, display: 'grid', gap: 16 }}>
|
||||||
<div>
|
<div>
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 6 }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 6 }}>
|
||||||
@@ -490,7 +486,7 @@ export const Settings = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{mode === 'auto-gradient' && (
|
{mode === 'cover-gradient' && (
|
||||||
<div style={{ marginBottom: 16 }}>
|
<div style={{ marginBottom: 16 }}>
|
||||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 6 }}>
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 6 }}>
|
||||||
<div style={{ color: 'rgba(255,255,255,0.8)', fontSize: 12 }}>Angle</div>
|
<div style={{ color: 'rgba(255,255,255,0.8)', fontSize: 12 }}>Angle</div>
|
||||||
@@ -531,7 +527,7 @@ export const Settings = () => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<AnySwitch
|
<AnySwitch
|
||||||
title="Exclude Inactive | Experimental"
|
title="Exclude Inactive"
|
||||||
desc="Apply color/gradient only to the currently active lyric line"
|
desc="Apply color/gradient only to the currently active lyric line"
|
||||||
checked={excludeInactive}
|
checked={excludeInactive}
|
||||||
onChange={(_: unknown, checked: boolean) => {
|
onChange={(_: unknown, checked: boolean) => {
|
||||||
|
|||||||
@@ -124,10 +124,10 @@ function applyGradient(start: string, end: string, angle: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resetModeClasses(): void {
|
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();
|
const img = await getCoverArtElement();
|
||||||
if (!img) return;
|
if (!img) return;
|
||||||
const colors = getDominantColorsFromImage(img, gradient ? 2 : 1);
|
const colors = getDominantColorsFromImage(img, gradient ? 2 : 1);
|
||||||
@@ -143,7 +143,7 @@ async function applyAutoColors(gradient: boolean) {
|
|||||||
|
|
||||||
function applyColoramaLyrics(): void {
|
function applyColoramaLyrics(): void {
|
||||||
if (!settings.enabled) {
|
if (!settings.enabled) {
|
||||||
document.body.classList.remove('colorama-single', 'colorama-gradient', 'colorama-rainbow');
|
document.body.classList.remove('colorama-single', 'colorama-gradient');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,17 +158,14 @@ function applyColoramaLyrics(): void {
|
|||||||
case "single":
|
case "single":
|
||||||
applySingleColor(settings.singleColor);
|
applySingleColor(settings.singleColor);
|
||||||
break;
|
break;
|
||||||
case "gradient":
|
case "gradient-experimental":
|
||||||
applyGradient(settings.gradientStart, settings.gradientEnd, settings.gradientAngle);
|
applyGradient(settings.gradientStart, settings.gradientEnd, settings.gradientAngle);
|
||||||
break;
|
break;
|
||||||
case "rainbow":
|
case "cover":
|
||||||
// no-op: rainbow mode disabled
|
applyCoverColors(false);
|
||||||
break;
|
break;
|
||||||
case "auto-single":
|
case "cover-gradient":
|
||||||
applyAutoColors(false);
|
applyCoverColors(true);
|
||||||
break;
|
|
||||||
case "auto-gradient":
|
|
||||||
applyAutoColors(true);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,7 +179,7 @@ function observeTrackChanges(): void {
|
|||||||
const currentTrackId = PlayState.playbackContext?.actualProductId;
|
const currentTrackId = PlayState.playbackContext?.actualProductId;
|
||||||
if (currentTrackId && currentTrackId !== lastTrackId) {
|
if (currentTrackId && currentTrackId !== lastTrackId) {
|
||||||
lastTrackId = currentTrackId;
|
lastTrackId = currentTrackId;
|
||||||
if (settings.mode.startsWith("auto")) {
|
if (settings.mode === 'cover' || settings.mode === 'cover-gradient') {
|
||||||
setTimeout(() => applyColoramaLyrics(), 200);
|
setTimeout(() => applyColoramaLyrics(), 200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,7 +217,6 @@ function hookRadiantUpdates(): void {
|
|||||||
|
|
||||||
setTimeout(() => hookRadiantUpdates(), 0);
|
setTimeout(() => hookRadiantUpdates(), 0);
|
||||||
|
|
||||||
// Observe active lyric span changes and restart rainbow animation to avoid freezes
|
// Rainbow mode removed
|
||||||
// Rainbow mode disabled: no lyrics observer needed
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,6 @@
|
|||||||
-webkit-text-fill-color: transparent !important;
|
-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 */
|
/* Only-active: apply container class only on the active line via JS */
|
||||||
|
|
||||||
/* Slight emphasis on current line (uniform to single mode) */
|
/* Slight emphasis on current line (uniform to single mode) */
|
||||||
|
|||||||
Reference in New Issue
Block a user