style: auto-fix linting issues
This commit is contained in:
parent
d1c56372a4
commit
fc2229dbf6
10 changed files with 3439 additions and 2377 deletions
5406
index.html
5406
index.html
File diff suppressed because one or more lines are too long
|
|
@ -4,77 +4,74 @@
|
||||||
import { equalizerSettings } from './storage.js';
|
import { equalizerSettings } from './storage.js';
|
||||||
|
|
||||||
// Standard 16-band ISO center frequencies (Hz)
|
// Standard 16-band ISO center frequencies (Hz)
|
||||||
const EQ_FREQUENCIES = [
|
const EQ_FREQUENCIES = [25, 40, 63, 100, 160, 250, 400, 630, 1000, 1600, 2500, 4000, 6300, 10000, 16000, 20000];
|
||||||
25, 40, 63, 100, 160, 250, 400, 630,
|
|
||||||
1000, 1600, 2500, 4000, 6300, 10000, 16000, 20000
|
|
||||||
];
|
|
||||||
|
|
||||||
// EQ Presets (gain values in dB for each of the 16 bands)
|
// EQ Presets (gain values in dB for each of the 16 bands)
|
||||||
const EQ_PRESETS = {
|
const EQ_PRESETS = {
|
||||||
flat: {
|
flat: {
|
||||||
name: 'Flat',
|
name: 'Flat',
|
||||||
gains: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
gains: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
},
|
},
|
||||||
bass_boost: {
|
bass_boost: {
|
||||||
name: 'Bass Boost',
|
name: 'Bass Boost',
|
||||||
gains: [6, 5, 4.5, 4, 3, 2, 1, 0.5, 0, 0, 0, 0, 0, 0, 0, 0]
|
gains: [6, 5, 4.5, 4, 3, 2, 1, 0.5, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
},
|
},
|
||||||
bass_reducer: {
|
bass_reducer: {
|
||||||
name: 'Bass Reducer',
|
name: 'Bass Reducer',
|
||||||
gains: [-6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
gains: [-6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
},
|
},
|
||||||
treble_boost: {
|
treble_boost: {
|
||||||
name: 'Treble Boost',
|
name: 'Treble Boost',
|
||||||
gains: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 5.5, 6]
|
gains: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 5.5, 6],
|
||||||
},
|
},
|
||||||
treble_reducer: {
|
treble_reducer: {
|
||||||
name: 'Treble Reducer',
|
name: 'Treble Reducer',
|
||||||
gains: [0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -2, -3, -4, -5, -5.5, -6]
|
gains: [0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -2, -3, -4, -5, -5.5, -6],
|
||||||
},
|
},
|
||||||
vocal_boost: {
|
vocal_boost: {
|
||||||
name: 'Vocal Boost',
|
name: 'Vocal Boost',
|
||||||
gains: [-2, -1, 0, 0, 1, 2, 3, 4, 4, 3, 2, 1, 0, 0, -1, -2]
|
gains: [-2, -1, 0, 0, 1, 2, 3, 4, 4, 3, 2, 1, 0, 0, -1, -2],
|
||||||
},
|
},
|
||||||
loudness: {
|
loudness: {
|
||||||
name: 'Loudness',
|
name: 'Loudness',
|
||||||
gains: [5, 4, 3, 1, 0, -1, -1, 0, 0, 1, 2, 3, 4, 4.5, 4, 3]
|
gains: [5, 4, 3, 1, 0, -1, -1, 0, 0, 1, 2, 3, 4, 4.5, 4, 3],
|
||||||
},
|
},
|
||||||
rock: {
|
rock: {
|
||||||
name: 'Rock',
|
name: 'Rock',
|
||||||
gains: [4, 3.5, 3, 2, -1, -2, -1, 1, 2, 3, 3.5, 4, 4, 3, 2, 1]
|
gains: [4, 3.5, 3, 2, -1, -2, -1, 1, 2, 3, 3.5, 4, 4, 3, 2, 1],
|
||||||
},
|
},
|
||||||
pop: {
|
pop: {
|
||||||
name: 'Pop',
|
name: 'Pop',
|
||||||
gains: [-1, 0, 1, 2, 3, 3, 2, 1, 0, 1, 2, 2, 2, 2, 1, 0]
|
gains: [-1, 0, 1, 2, 3, 3, 2, 1, 0, 1, 2, 2, 2, 2, 1, 0],
|
||||||
},
|
},
|
||||||
classical: {
|
classical: {
|
||||||
name: 'Classical',
|
name: 'Classical',
|
||||||
gains: [3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 2]
|
gains: [3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 2],
|
||||||
},
|
},
|
||||||
jazz: {
|
jazz: {
|
||||||
name: 'Jazz',
|
name: 'Jazz',
|
||||||
gains: [3, 2, 1, 1, -1, -1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2]
|
gains: [3, 2, 1, 1, -1, -1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2],
|
||||||
},
|
},
|
||||||
electronic: {
|
electronic: {
|
||||||
name: 'Electronic',
|
name: 'Electronic',
|
||||||
gains: [4, 3.5, 3, 1, 0, -1, 0, 1, 2, 3, 3, 2, 2, 3, 4, 3.5]
|
gains: [4, 3.5, 3, 1, 0, -1, 0, 1, 2, 3, 3, 2, 2, 3, 4, 3.5],
|
||||||
},
|
},
|
||||||
hip_hop: {
|
hip_hop: {
|
||||||
name: 'Hip-Hop',
|
name: 'Hip-Hop',
|
||||||
gains: [5, 4.5, 4, 3, 1, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2]
|
gains: [5, 4.5, 4, 3, 1, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2],
|
||||||
},
|
},
|
||||||
r_and_b: {
|
r_and_b: {
|
||||||
name: 'R&B',
|
name: 'R&B',
|
||||||
gains: [3, 5, 4, 2, 1, 0, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1]
|
gains: [3, 5, 4, 2, 1, 0, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1],
|
||||||
},
|
},
|
||||||
acoustic: {
|
acoustic: {
|
||||||
name: 'Acoustic',
|
name: 'Acoustic',
|
||||||
gains: [3, 2, 1, 1, 2, 2, 1, 0, 0, 1, 1, 2, 3, 3, 2, 1]
|
gains: [3, 2, 1, 1, 2, 2, 1, 0, 0, 1, 1, 2, 3, 3, 2, 1],
|
||||||
},
|
},
|
||||||
podcast: {
|
podcast: {
|
||||||
name: 'Podcast / Speech',
|
name: 'Podcast / Speech',
|
||||||
gains: [-3, -2, -1, 0, 1, 2, 3, 4, 4, 3, 2, 1, 0, -1, -2, -3]
|
gains: [-3, -2, -1, 0, 1, 2, 3, 4, 4, 3, 2, 1, 0, -1, -2, -3],
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
class AudioContextManager {
|
class AudioContextManager {
|
||||||
|
|
@ -174,7 +171,7 @@ class AudioContextManager {
|
||||||
// Fallback: direct connection
|
// Fallback: direct connection
|
||||||
try {
|
try {
|
||||||
this.source.connect(this.audioContext.destination);
|
this.source.connect(this.audioContext.destination);
|
||||||
} catch { }
|
} catch {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,83 +4,94 @@
|
||||||
import { equalizerSettings } from './storage.js';
|
import { equalizerSettings } from './storage.js';
|
||||||
|
|
||||||
// Standard 16-band ISO center frequencies (Hz)
|
// Standard 16-band ISO center frequencies (Hz)
|
||||||
const EQ_FREQUENCIES = [
|
const EQ_FREQUENCIES = [25, 40, 63, 100, 160, 250, 400, 630, 1000, 1600, 2500, 4000, 6300, 10000, 16000, 20000];
|
||||||
25, 40, 63, 100, 160, 250, 400, 630,
|
|
||||||
1000, 1600, 2500, 4000, 6300, 10000, 16000, 20000
|
|
||||||
];
|
|
||||||
|
|
||||||
// Frequency labels for UI display
|
// Frequency labels for UI display
|
||||||
const FREQUENCY_LABELS = [
|
const FREQUENCY_LABELS = [
|
||||||
'25', '40', '63', '100', '160', '250', '400', '630',
|
'25',
|
||||||
'1K', '1.6K', '2.5K', '4K', '6.3K', '10K', '16K', '20K'
|
'40',
|
||||||
|
'63',
|
||||||
|
'100',
|
||||||
|
'160',
|
||||||
|
'250',
|
||||||
|
'400',
|
||||||
|
'630',
|
||||||
|
'1K',
|
||||||
|
'1.6K',
|
||||||
|
'2.5K',
|
||||||
|
'4K',
|
||||||
|
'6.3K',
|
||||||
|
'10K',
|
||||||
|
'16K',
|
||||||
|
'20K',
|
||||||
];
|
];
|
||||||
|
|
||||||
// EQ Presets (gain values in dB for each of the 16 bands)
|
// EQ Presets (gain values in dB for each of the 16 bands)
|
||||||
const EQ_PRESETS = {
|
const EQ_PRESETS = {
|
||||||
flat: {
|
flat: {
|
||||||
name: 'Flat',
|
name: 'Flat',
|
||||||
gains: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
gains: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
},
|
},
|
||||||
bass_boost: {
|
bass_boost: {
|
||||||
name: 'Bass Boost',
|
name: 'Bass Boost',
|
||||||
gains: [6, 5, 4.5, 4, 3, 2, 1, 0.5, 0, 0, 0, 0, 0, 0, 0, 0]
|
gains: [6, 5, 4.5, 4, 3, 2, 1, 0.5, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
},
|
},
|
||||||
bass_reducer: {
|
bass_reducer: {
|
||||||
name: 'Bass Reducer',
|
name: 'Bass Reducer',
|
||||||
gains: [-6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
gains: [-6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
},
|
},
|
||||||
treble_boost: {
|
treble_boost: {
|
||||||
name: 'Treble Boost',
|
name: 'Treble Boost',
|
||||||
gains: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 5.5, 6]
|
gains: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 5.5, 6],
|
||||||
},
|
},
|
||||||
treble_reducer: {
|
treble_reducer: {
|
||||||
name: 'Treble Reducer',
|
name: 'Treble Reducer',
|
||||||
gains: [0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -2, -3, -4, -5, -5.5, -6]
|
gains: [0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -2, -3, -4, -5, -5.5, -6],
|
||||||
},
|
},
|
||||||
vocal_boost: {
|
vocal_boost: {
|
||||||
name: 'Vocal Boost',
|
name: 'Vocal Boost',
|
||||||
gains: [-2, -1, 0, 0, 1, 2, 3, 4, 4, 3, 2, 1, 0, 0, -1, -2]
|
gains: [-2, -1, 0, 0, 1, 2, 3, 4, 4, 3, 2, 1, 0, 0, -1, -2],
|
||||||
},
|
},
|
||||||
loudness: {
|
loudness: {
|
||||||
name: 'Loudness',
|
name: 'Loudness',
|
||||||
gains: [5, 4, 3, 1, 0, -1, -1, 0, 0, 1, 2, 3, 4, 4.5, 4, 3]
|
gains: [5, 4, 3, 1, 0, -1, -1, 0, 0, 1, 2, 3, 4, 4.5, 4, 3],
|
||||||
},
|
},
|
||||||
rock: {
|
rock: {
|
||||||
name: 'Rock',
|
name: 'Rock',
|
||||||
gains: [4, 3.5, 3, 2, -1, -2, -1, 1, 2, 3, 3.5, 4, 4, 3, 2, 1]
|
gains: [4, 3.5, 3, 2, -1, -2, -1, 1, 2, 3, 3.5, 4, 4, 3, 2, 1],
|
||||||
},
|
},
|
||||||
pop: {
|
pop: {
|
||||||
name: 'Pop',
|
name: 'Pop',
|
||||||
gains: [-1, 0, 1, 2, 3, 3, 2, 1, 0, 1, 2, 2, 2, 2, 1, 0]
|
gains: [-1, 0, 1, 2, 3, 3, 2, 1, 0, 1, 2, 2, 2, 2, 1, 0],
|
||||||
},
|
},
|
||||||
classical: {
|
classical: {
|
||||||
name: 'Classical',
|
name: 'Classical',
|
||||||
gains: [3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 2]
|
gains: [3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 2],
|
||||||
},
|
},
|
||||||
jazz: {
|
jazz: {
|
||||||
name: 'Jazz',
|
name: 'Jazz',
|
||||||
gains: [3, 2, 1, 1, -1, -1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2]
|
gains: [3, 2, 1, 1, -1, -1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2],
|
||||||
},
|
},
|
||||||
electronic: {
|
electronic: {
|
||||||
name: 'Electronic',
|
name: 'Electronic',
|
||||||
gains: [4, 3.5, 3, 1, 0, -1, 0, 1, 2, 3, 3, 2, 2, 3, 4, 3.5]
|
gains: [4, 3.5, 3, 1, 0, -1, 0, 1, 2, 3, 3, 2, 2, 3, 4, 3.5],
|
||||||
},
|
},
|
||||||
hip_hop: {
|
hip_hop: {
|
||||||
name: 'Hip-Hop',
|
name: 'Hip-Hop',
|
||||||
gains: [5, 4.5, 4, 3, 1, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2]
|
gains: [5, 4.5, 4, 3, 1, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2],
|
||||||
},
|
},
|
||||||
r_and_b: {
|
r_and_b: {
|
||||||
name: 'R&B',
|
name: 'R&B',
|
||||||
gains: [3, 5, 4, 2, 1, 0, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1]
|
gains: [3, 5, 4, 2, 1, 0, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1],
|
||||||
},
|
},
|
||||||
acoustic: {
|
acoustic: {
|
||||||
name: 'Acoustic',
|
name: 'Acoustic',
|
||||||
gains: [3, 2, 1, 1, 2, 2, 1, 0, 0, 1, 1, 2, 3, 3, 2, 1]
|
gains: [3, 2, 1, 1, 2, 2, 1, 0, 0, 1, 1, 2, 3, 3, 2, 1],
|
||||||
},
|
},
|
||||||
podcast: {
|
podcast: {
|
||||||
name: 'Podcast / Speech',
|
name: 'Podcast / Speech',
|
||||||
gains: [-3, -2, -1, 0, 1, 2, 3, 4, 4, 3, 2, 1, 0, -1, -2, -3]
|
gains: [-3, -2, -1, 0, 1, 2, 3, 4, 4, 3, 2, 1, 0, -1, -2, -3],
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Equalizer {
|
export class Equalizer {
|
||||||
|
|
@ -227,9 +238,11 @@ export class Equalizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispatch event for visualizer to reconnect
|
// Dispatch event for visualizer to reconnect
|
||||||
window.dispatchEvent(new CustomEvent('equalizer-toggle', {
|
window.dispatchEvent(
|
||||||
detail: { enabled }
|
new CustomEvent('equalizer-toggle', {
|
||||||
}));
|
detail: { enabled },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
return this.isEnabled;
|
return this.isEnabled;
|
||||||
}
|
}
|
||||||
|
|
@ -338,12 +351,18 @@ export class Equalizer {
|
||||||
* Destroy the equalizer
|
* Destroy the equalizer
|
||||||
*/
|
*/
|
||||||
destroy() {
|
destroy() {
|
||||||
this.filters.forEach(filter => {
|
this.filters.forEach((filter) => {
|
||||||
try { filter.disconnect(); } catch { }
|
try {
|
||||||
|
filter.disconnect();
|
||||||
|
} catch {}
|
||||||
});
|
});
|
||||||
|
|
||||||
try { this.inputNode?.disconnect(); } catch { }
|
try {
|
||||||
try { this.outputNode?.disconnect(); } catch { }
|
this.inputNode?.disconnect();
|
||||||
|
} catch {}
|
||||||
|
try {
|
||||||
|
this.outputNode?.disconnect();
|
||||||
|
} catch {}
|
||||||
|
|
||||||
this.filters = [];
|
this.filters = [];
|
||||||
this.inputNode = null;
|
this.inputNode = null;
|
||||||
|
|
|
||||||
76
js/events.js
76
js/events.js
|
|
@ -618,10 +618,11 @@ export async function showAddToPlaylistModal(track) {
|
||||||
return `
|
return `
|
||||||
<div class="modal-option ${alreadyContains ? 'already-contains' : ''}" data-id="${p.id}">
|
<div class="modal-option ${alreadyContains ? 'already-contains' : ''}" data-id="${p.id}">
|
||||||
<span>${p.name}</span>
|
<span>${p.name}</span>
|
||||||
${alreadyContains
|
${
|
||||||
|
alreadyContains
|
||||||
? `<button class="remove-from-playlist-btn-modal" title="Remove from playlist" style="background: transparent; border: none; color: inherit; cursor: pointer; padding: 4px; display: flex; align-items: center;">${SVG_BIN}</button>`
|
? `<button class="remove-from-playlist-btn-modal" title="Remove from playlist" style="background: transparent; border: none; color: inherit; cursor: pointer; padding: 4px; display: flex; align-items: center;">${SVG_BIN}</button>`
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
})
|
})
|
||||||
|
|
@ -968,10 +969,11 @@ export async function handleTrackAction(
|
||||||
return `
|
return `
|
||||||
<div class="modal-option ${alreadyContains ? 'already-contains' : ''}" data-id="${p.id}">
|
<div class="modal-option ${alreadyContains ? 'already-contains' : ''}" data-id="${p.id}">
|
||||||
<span>${p.name}</span>
|
<span>${p.name}</span>
|
||||||
${alreadyContains
|
${
|
||||||
|
alreadyContains
|
||||||
? `<button class="remove-from-playlist-btn-modal" title="Remove from playlist" style="background: transparent; border: none; color: inherit; cursor: pointer; padding: 4px; display: flex; align-items: center;">${SVG_BIN}</button>`
|
? `<button class="remove-from-playlist-btn-modal" title="Remove from playlist" style="background: transparent; border: none; color: inherit; cursor: pointer; padding: 4px; display: flex; align-items: center;">${SVG_BIN}</button>`
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
})
|
})
|
||||||
|
|
@ -1090,28 +1092,31 @@ export async function handleTrackAction(
|
||||||
${item.trackerInfo.recordingDate ? `<p><strong style="color: var(--foreground);">Recording Date:</strong> ${new Date(item.trackerInfo.recordingDate).toLocaleDateString()}</p>` : ''}
|
${item.trackerInfo.recordingDate ? `<p><strong style="color: var(--foreground);">Recording Date:</strong> ${new Date(item.trackerInfo.recordingDate).toLocaleDateString()}</p>` : ''}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${item.trackerInfo.description
|
${
|
||||||
? `
|
item.trackerInfo.description
|
||||||
|
? `
|
||||||
<div style="margin-top: 1rem; padding: 0.75rem; background: var(--accent); border-radius: 8px;">
|
<div style="margin-top: 1rem; padding: 0.75rem; background: var(--accent); border-radius: 8px;">
|
||||||
<p style="color: var(--foreground); font-weight: 500; margin-bottom: 0.5rem;">Description</p>
|
<p style="color: var(--foreground); font-weight: 500; margin-bottom: 0.5rem;">Description</p>
|
||||||
<p style="font-size: 0.85rem; line-height: 1.6;">${item.trackerInfo.description}</p>
|
<p style="font-size: 0.85rem; line-height: 1.6;">${item.trackerInfo.description}</p>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
${item.trackerInfo.notes
|
${
|
||||||
? `
|
item.trackerInfo.notes
|
||||||
|
? `
|
||||||
<div style="margin-top: 1rem; padding: 0.75rem; background: var(--accent); border-radius: 8px;">
|
<div style="margin-top: 1rem; padding: 0.75rem; background: var(--accent); border-radius: 8px;">
|
||||||
<p style="color: var(--foreground); font-weight: 500; margin-bottom: 0.5rem;">Notes</p>
|
<p style="color: var(--foreground); font-weight: 500; margin-bottom: 0.5rem;">Notes</p>
|
||||||
<p style="font-size: 0.85rem; line-height: 1.6;">${item.trackerInfo.notes}</p>
|
<p style="font-size: 0.85rem; line-height: 1.6;">${item.trackerInfo.notes}</p>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
${item.trackerInfo.sourceUrl
|
${
|
||||||
? `
|
item.trackerInfo.sourceUrl
|
||||||
|
? `
|
||||||
<div style="margin-top: 1rem;">
|
<div style="margin-top: 1rem;">
|
||||||
<p style="margin-bottom: 0.5rem;"><strong style="color: var(--foreground);">Source URL:</strong></p>
|
<p style="margin-bottom: 0.5rem;"><strong style="color: var(--foreground);">Source URL:</strong></p>
|
||||||
<a href="${item.trackerInfo.sourceUrl}" target="_blank" style="color: var(--primary); word-break: break-all; font-size: 0.85rem; display: block; padding: 0.5rem; background: var(--accent); border-radius: 6px; text-decoration: none;">
|
<a href="${item.trackerInfo.sourceUrl}" target="_blank" style="color: var(--primary); word-break: break-all; font-size: 0.85rem; display: block; padding: 0.5rem; background: var(--accent); border-radius: 6px; text-decoration: none;">
|
||||||
|
|
@ -1119,8 +1124,8 @@ export async function handleTrackAction(
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
${item.id ? `<p style="margin-top: 1rem; font-size: 0.8rem; color: var(--muted);"><strong>Track ID:</strong> ${item.id}</p>` : ''}
|
${item.id ? `<p style="margin-top: 1rem; font-size: 0.8rem; color: var(--muted);"><strong>Track ID:</strong> ${item.id}</p>` : ''}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1151,8 +1156,9 @@ export async function handleTrackAction(
|
||||||
<p><strong style="color: var(--foreground);">Quality:</strong> ${quality} ${bitrate ? `(${bitrate})` : ''}</p>
|
<p><strong style="color: var(--foreground);">Quality:</strong> ${quality} ${bitrate ? `(${bitrate})` : ''}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${item.credits && item.credits.length > 0
|
${
|
||||||
? `
|
item.credits && item.credits.length > 0
|
||||||
|
? `
|
||||||
<div style="margin-top: 1rem; padding: 0.75rem; background: var(--accent); border-radius: 8px;">
|
<div style="margin-top: 1rem; padding: 0.75rem; background: var(--accent); border-radius: 8px;">
|
||||||
<p style="color: var(--foreground); font-weight: 500; margin-bottom: 0.5rem;">Credits</p>
|
<p style="color: var(--foreground); font-weight: 500; margin-bottom: 0.5rem;">Credits</p>
|
||||||
<div style="font-size: 0.85rem; line-height: 1.6;">
|
<div style="font-size: 0.85rem; line-height: 1.6;">
|
||||||
|
|
@ -1160,24 +1166,26 @@ export async function handleTrackAction(
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
${item.composers && item.composers.length > 0
|
${
|
||||||
? `
|
item.composers && item.composers.length > 0
|
||||||
|
? `
|
||||||
<p style="margin-top: 0.5rem;"><strong style="color: var(--foreground);">Composers:</strong> ${item.composers.map((c) => c.name).join(', ')}</p>
|
<p style="margin-top: 0.5rem;"><strong style="color: var(--foreground);">Composers:</strong> ${item.composers.map((c) => c.name).join(', ')}</p>
|
||||||
`
|
`
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
${item.lyrics?.text
|
${
|
||||||
? `
|
item.lyrics?.text
|
||||||
|
? `
|
||||||
<div style="margin-top: 1rem; padding: 0.75rem; background: var(--accent); border-radius: 8px;">
|
<div style="margin-top: 1rem; padding: 0.75rem; background: var(--accent); border-radius: 8px;">
|
||||||
<p style="color: var(--foreground); font-weight: 500; margin-bottom: 0.5rem;">Has Lyrics</p>
|
<p style="color: var(--foreground); font-weight: 500; margin-bottom: 0.5rem;">Has Lyrics</p>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
${item.id ? `<p style="margin-top: 1rem; font-size: 0.8rem; color: var(--muted);"><strong>Track ID:</strong> ${item.id}</p>` : ''}
|
${item.id ? `<p style="margin-top: 1rem; font-size: 0.8rem; color: var(--muted);"><strong>Track ID:</strong> ${item.id}</p>` : ''}
|
||||||
${item.album?.id ? `<p style="font-size: 0.8rem; color: var(--muted);"><strong>Album ID:</strong> ${item.album.id}</p>` : ''}
|
${item.album?.id ? `<p style="font-size: 0.8rem; color: var(--muted);"><strong>Album ID:</strong> ${item.album.id}</p>` : ''}
|
||||||
|
|
@ -1452,12 +1460,12 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen
|
||||||
const type = card.dataset.albumId
|
const type = card.dataset.albumId
|
||||||
? 'album'
|
? 'album'
|
||||||
: card.dataset.playlistId
|
: card.dataset.playlistId
|
||||||
? 'playlist'
|
? 'playlist'
|
||||||
: card.dataset.mixId
|
: card.dataset.mixId
|
||||||
? 'mix'
|
? 'mix'
|
||||||
: card.dataset.href
|
: card.dataset.href
|
||||||
? card.dataset.href.split('/')[1]
|
? card.dataset.href.split('/')[1]
|
||||||
: 'item';
|
: 'item';
|
||||||
const id = card.dataset.albumId || card.dataset.playlistId || card.dataset.mixId;
|
const id = card.dataset.albumId || card.dataset.playlistId || card.dataset.mixId;
|
||||||
|
|
||||||
const item = trackDataStore.get(card) || {
|
const item = trackDataStore.get(card) || {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import { listenBrainzSettings } from './storage.js';
|
import { listenBrainzSettings } from './storage.js';
|
||||||
|
|
||||||
export class ListenBrainzScrobbler {
|
export class ListenBrainzScrobbler {
|
||||||
|
|
@ -46,7 +45,7 @@ export class ListenBrainzScrobbler {
|
||||||
additional_info: {
|
additional_info: {
|
||||||
submission_client: 'Monochrome',
|
submission_client: 'Monochrome',
|
||||||
submission_client_version: '1.0.0',
|
submission_client_version: '1.0.0',
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (track.album?.title) {
|
if (track.album?.title) {
|
||||||
|
|
@ -77,7 +76,7 @@ export class ListenBrainzScrobbler {
|
||||||
const payload = [
|
const payload = [
|
||||||
{
|
{
|
||||||
track_metadata: metadata,
|
track_metadata: metadata,
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
if (timestamp) {
|
if (timestamp) {
|
||||||
|
|
@ -86,17 +85,17 @@ export class ListenBrainzScrobbler {
|
||||||
|
|
||||||
const body = {
|
const body = {
|
||||||
listen_type: listenType,
|
listen_type: listenType,
|
||||||
payload: payload
|
payload: payload,
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${this.API_URL}/submit-listens`, {
|
const response = await fetch(`${this.API_URL}/submit-listens`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': `Token ${this.getToken()}`,
|
Authorization: `Token ${this.getToken()}`,
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify(body)
|
body: JSON.stringify(body),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import { LastFMScrobbler } from './lastfm.js';
|
import { LastFMScrobbler } from './lastfm.js';
|
||||||
import { ListenBrainzScrobbler } from './listenbrainz.js';
|
import { ListenBrainzScrobbler } from './listenbrainz.js';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ export function initializeSettings(scrobbler, player, api, ui) {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await authManager.sendPasswordReset(email);
|
await authManager.sendPasswordReset(email);
|
||||||
} catch { }
|
} catch {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -243,9 +243,6 @@ export function initializeSettings(scrobbler, player, api, ui) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Theme picker
|
// Theme picker
|
||||||
const themePicker = document.getElementById('theme-picker');
|
const themePicker = document.getElementById('theme-picker');
|
||||||
const currentTheme = themeManager.getTheme();
|
const currentTheme = themeManager.getTheme();
|
||||||
|
|
@ -497,9 +494,7 @@ export function initializeSettings(scrobbler, player, api, ui) {
|
||||||
const currentPreset = EQ_PRESETS[eqPresetSelect.value];
|
const currentPreset = EQ_PRESETS[eqPresetSelect.value];
|
||||||
if (currentPreset) {
|
if (currentPreset) {
|
||||||
const currentGains = audioContextManager.getGains();
|
const currentGains = audioContextManager.getGains();
|
||||||
const matches = currentPreset.gains.every(
|
const matches = currentPreset.gains.every((g, i) => Math.abs(g - currentGains[i]) < 0.01);
|
||||||
(g, i) => Math.abs(g - currentGains[i]) < 0.01
|
|
||||||
);
|
|
||||||
if (!matches) {
|
if (!matches) {
|
||||||
// Don't change the select, but the preset will save as 'custom'
|
// Don't change the select, but the preset will save as 'custom'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -784,7 +784,7 @@ export const equalizerSettings = {
|
||||||
return gains;
|
return gains;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch { }
|
} catch {}
|
||||||
// Return flat EQ (all zeros) by default
|
// Return flat EQ (all zeros) by default
|
||||||
return new Array(16).fill(0);
|
return new Array(16).fill(0);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ export class Visualizer {
|
||||||
try {
|
try {
|
||||||
this.source.connect(this.analyser);
|
this.source.connect(this.analyser);
|
||||||
this.analyser.connect(this.audioContext.destination);
|
this.analyser.connect(this.audioContext.destination);
|
||||||
} catch { }
|
} catch {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
183
styles.css
183
styles.css
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
/* Layout */
|
/* Layout */
|
||||||
--radius: 0.75rem;
|
--radius: 0.75rem;
|
||||||
|
|
||||||
/* Slightly more rounded for modern feel */
|
/* Slightly more rounded for modern feel */
|
||||||
--radius-sm: 0.5rem;
|
--radius-sm: 0.5rem;
|
||||||
--radius-full: 9999px;
|
--radius-full: 9999px;
|
||||||
|
|
@ -26,6 +27,7 @@
|
||||||
--ease-out-back: cubic-bezier(0.34, 1.56, 0.64, 1);
|
--ease-out-back: cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||||
--ease-elastic: cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
--ease-elastic: cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||||||
--transition: var(--transition-normal);
|
--transition: var(--transition-normal);
|
||||||
|
|
||||||
/* Fallback */
|
/* Fallback */
|
||||||
|
|
||||||
/* Shadows (layered for depth) */
|
/* Shadows (layered for depth) */
|
||||||
|
|
@ -35,7 +37,6 @@
|
||||||
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
||||||
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
||||||
--shadow-glow: 0 0 15px var(--highlight-rgb);
|
--shadow-glow: 0 0 15px var(--highlight-rgb);
|
||||||
|
|
||||||
--cover-filter: blur(50px) brightness(0.4);
|
--cover-filter: blur(50px) brightness(0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -418,12 +419,14 @@ kbd {
|
||||||
left: calc(190px + 2%);
|
left: calc(190px + 2%);
|
||||||
bottom: 15px !important;
|
bottom: 15px !important;
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
|
|
||||||
/* Standardized radius */
|
/* Standardized radius */
|
||||||
position: fixed !important;
|
position: fixed !important;
|
||||||
background-color: color-mix(in srgb, var(--card) 85%, transparent);
|
background-color: color-mix(in srgb, var(--card) 85%, transparent);
|
||||||
backdrop-filter: blur(20px);
|
backdrop-filter: blur(20px);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
box-shadow: var(--shadow-2xl);
|
box-shadow: var(--shadow-2xl);
|
||||||
|
|
||||||
/* Standardized shadow */
|
/* Standardized shadow */
|
||||||
transition: all var(--transition-normal) var(--ease-out-back);
|
transition: all var(--transition-normal) var(--ease-out-back);
|
||||||
height: var(--player-bar-height-desktop);
|
height: var(--player-bar-height-desktop);
|
||||||
|
|
@ -432,7 +435,7 @@ kbd {
|
||||||
|
|
||||||
:root[data-theme='light'] .now-playing-bar {
|
:root[data-theme='light'] .now-playing-bar {
|
||||||
background-color: color-mix(in srgb, var(--card) 80%, transparent);
|
background-color: color-mix(in srgb, var(--card) 80%, transparent);
|
||||||
border-color: rgba(0, 0, 0, 0.1);
|
border-color: rgb(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-logo {
|
.sidebar-logo {
|
||||||
|
|
@ -474,7 +477,10 @@ kbd {
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
color: var(--muted-foreground);
|
color: var(--muted-foreground);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
transition: background-color var(--transition-fast), color var(--transition-fast), transform var(--transition-fast);
|
transition:
|
||||||
|
background-color var(--transition-fast),
|
||||||
|
color var(--transition-fast),
|
||||||
|
transform var(--transition-fast);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -493,6 +499,7 @@ kbd {
|
||||||
background-color: var(--secondary);
|
background-color: var(--secondary);
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
transform: translateX(4px);
|
transform: translateX(4px);
|
||||||
|
|
||||||
/* Slide effect */
|
/* Slide effect */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -538,13 +545,17 @@ kbd {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background-color: var(--card);
|
background-color: var(--card);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
|
|
||||||
/* Better definition */
|
/* Better definition */
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: transform var(--transition-fast), background-color var(--transition-fast), box-shadow var(--transition-fast);
|
transition:
|
||||||
|
transform var(--transition-fast),
|
||||||
|
background-color var(--transition-fast),
|
||||||
|
box-shadow var(--transition-fast);
|
||||||
box-shadow: var(--shadow-sm);
|
box-shadow: var(--shadow-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -591,13 +602,16 @@ kbd {
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
transition: box-shadow var(--transition-fast), border-color var(--transition-fast), background-color var(--transition-fast);
|
transition:
|
||||||
|
box-shadow var(--transition-fast),
|
||||||
|
border-color var(--transition-fast),
|
||||||
|
background-color var(--transition-fast);
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-bar input:focus {
|
.search-bar input:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: var(--ring);
|
border-color: var(--ring);
|
||||||
box-shadow: 0 0 0 3px rgba(var(--highlight-rgb), 0.2);
|
box-shadow: 0 0 0 3px rgb(var(--highlight-rgb), 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
body.has-page-background .search-bar input {
|
body.has-page-background .search-bar input {
|
||||||
|
|
@ -778,7 +792,6 @@ input[type='search']::-webkit-search-cancel-button {
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes pulse {
|
@keyframes pulse {
|
||||||
|
|
||||||
0%,
|
0%,
|
||||||
100% {
|
100% {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
|
@ -847,16 +860,22 @@ input[type='search']::-webkit-search-cancel-button {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
border-bottom: 2px solid transparent;
|
border-bottom: 2px solid transparent;
|
||||||
|
|
||||||
/* Keep layout stable */
|
/* Keep layout stable */
|
||||||
border-radius: var(--radius-sm) var(--radius-sm) 0 0;
|
border-radius: var(--radius-sm) var(--radius-sm) 0 0;
|
||||||
transition: color var(--transition-fast), background-color var(--transition-fast), transform var(--transition-fast);
|
transition:
|
||||||
|
color var(--transition-fast),
|
||||||
|
background-color var(--transition-fast),
|
||||||
|
transform var(--transition-fast);
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
/* For Pseudo-elements if needed later */
|
/* For Pseudo-elements if needed later */
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-tab:hover {
|
.search-tab:hover {
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
background-color: rgba(var(--highlight-rgb), 0.05);
|
background-color: rgb(var(--highlight-rgb), 0.05);
|
||||||
|
|
||||||
/* Subtle highlight */
|
/* Subtle highlight */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -876,6 +895,7 @@ input[type='search']::-webkit-search-cancel-button {
|
||||||
.search-tab-content.active {
|
.search-tab-content.active {
|
||||||
display: block;
|
display: block;
|
||||||
animation: fade-in-slide-up 0.4s var(--ease-out-back);
|
animation: fade-in-slide-up 0.4s var(--ease-out-back);
|
||||||
|
|
||||||
/* Use standardized animation */
|
/* Use standardized animation */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -890,7 +910,10 @@ input[type='search']::-webkit-search-cancel-button {
|
||||||
background-color: var(--card);
|
background-color: var(--card);
|
||||||
padding: var(--spacing-md);
|
padding: var(--spacing-md);
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
transition: transform var(--transition-normal), box-shadow var(--transition-normal), background-color var(--transition-normal);
|
transition:
|
||||||
|
transform var(--transition-normal),
|
||||||
|
box-shadow var(--transition-normal),
|
||||||
|
background-color var(--transition-normal);
|
||||||
position: relative;
|
position: relative;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
@ -907,11 +930,13 @@ input[type='search']::-webkit-search-cancel-button {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-bottom: var(--spacing-md);
|
margin-bottom: var(--spacing-md);
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
|
|
||||||
/* Ensure images inherit standard radius */
|
/* Ensure images inherit standard radius */
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-shadow: var(--shadow-md);
|
box-shadow: var(--shadow-md);
|
||||||
transition: box-shadow var(--transition-normal);
|
transition: box-shadow var(--transition-normal);
|
||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
|
|
||||||
/* Enforce square aspect ratio */
|
/* Enforce square aspect ratio */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -929,6 +954,7 @@ input[type='search']::-webkit-search-cancel-button {
|
||||||
|
|
||||||
.card:hover .card-image {
|
.card:hover .card-image {
|
||||||
transform: scale(1.05);
|
transform: scale(1.05);
|
||||||
|
|
||||||
/* Subtle zoom */
|
/* Subtle zoom */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -959,10 +985,13 @@ input[type='search']::-webkit-search-cancel-button {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: scale(0.8);
|
transform: scale(0.8);
|
||||||
transition: transform var(--transition-fast), opacity var(--transition-fast), background-color var(--transition-fast) !important;
|
transition:
|
||||||
|
transform var(--transition-fast),
|
||||||
|
opacity var(--transition-fast),
|
||||||
|
background-color var(--transition-fast) !important;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
color: white !important;
|
color: white !important;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1) !important;
|
border: 1px solid rgb(255, 255, 255, 0.1) !important;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -974,6 +1003,7 @@ input[type='search']::-webkit-search-cancel-button {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
transition-delay: 0.05s;
|
transition-delay: 0.05s;
|
||||||
|
|
||||||
/* Slight delay for staggered feel */
|
/* Slight delay for staggered feel */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -983,8 +1013,9 @@ input[type='search']::-webkit-search-cancel-button {
|
||||||
.delete-playlist-btn:hover {
|
.delete-playlist-btn:hover {
|
||||||
background: rgb(0, 0, 0, 0.7) !important;
|
background: rgb(0, 0, 0, 0.7) !important;
|
||||||
transform: scale(1.1) rotate(5deg) !important;
|
transform: scale(1.1) rotate(5deg) !important;
|
||||||
|
|
||||||
/* Playful rotation */
|
/* Playful rotation */
|
||||||
border-color: rgba(255, 255, 255, 0.3) !important;
|
border-color: rgb(255, 255, 255, 0.3) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-like-btn.active {
|
.card-like-btn.active {
|
||||||
|
|
@ -1126,7 +1157,6 @@ input[type='search']::-webkit-search-cancel-button {
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1100px) {
|
@media (max-width: 1100px) {
|
||||||
|
|
||||||
#home-recommended-songs,
|
#home-recommended-songs,
|
||||||
#artist-detail-tracks,
|
#artist-detail-tracks,
|
||||||
#playlist-detail-recommended {
|
#playlist-detail-recommended {
|
||||||
|
|
@ -1220,7 +1250,9 @@ input[type='search']::-webkit-search-cancel-button {
|
||||||
padding: var(--spacing-sm) var(--spacing-md);
|
padding: var(--spacing-sm) var(--spacing-md);
|
||||||
border-radius: var(--radius-sm);
|
border-radius: var(--radius-sm);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
transition: background-color var(--transition-fast), transform var(--transition-fast);
|
transition:
|
||||||
|
background-color var(--transition-fast),
|
||||||
|
transform var(--transition-fast);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
@ -1228,6 +1260,7 @@ input[type='search']::-webkit-search-cancel-button {
|
||||||
.track-item:hover {
|
.track-item:hover {
|
||||||
background-color: var(--secondary);
|
background-color: var(--secondary);
|
||||||
transform: scale(1.005);
|
transform: scale(1.005);
|
||||||
|
|
||||||
/* Micro interaction */
|
/* Micro interaction */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1508,6 +1541,7 @@ input[type='search']::-webkit-search-cancel-button {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
padding: 0.75rem 1.5rem;
|
padding: 0.75rem 1.5rem;
|
||||||
|
|
||||||
/* Adjusted for consistency */
|
/* Adjusted for consistency */
|
||||||
background-color: var(--primary);
|
background-color: var(--primary);
|
||||||
color: var(--primary-foreground);
|
color: var(--primary-foreground);
|
||||||
|
|
@ -1516,7 +1550,10 @@ input[type='search']::-webkit-search-cancel-button {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: transform var(--transition-fast), box-shadow var(--transition-fast), filter var(--transition-fast);
|
transition:
|
||||||
|
transform var(--transition-fast),
|
||||||
|
box-shadow var(--transition-fast),
|
||||||
|
filter var(--transition-fast);
|
||||||
box-shadow: var(--shadow-sm);
|
box-shadow: var(--shadow-sm);
|
||||||
-webkit-tap-highlight-color: transparent;
|
-webkit-tap-highlight-color: transparent;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
@ -1527,6 +1564,7 @@ input[type='search']::-webkit-search-cancel-button {
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
box-shadow: var(--shadow-glow);
|
box-shadow: var(--shadow-glow);
|
||||||
filter: brightness(1.1);
|
filter: brightness(1.1);
|
||||||
|
|
||||||
/* Brighter instead of darker */
|
/* Brighter instead of darker */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1695,7 +1733,8 @@ input[type='search']::-webkit-search-cancel-button {
|
||||||
background-color: var(--secondary);
|
background-color: var(--secondary);
|
||||||
transition: background-color var(--transition-normal);
|
transition: background-color var(--transition-normal);
|
||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
|
box-shadow: inset 0 2px 4px rgb(0, 0, 0, 0.1);
|
||||||
|
|
||||||
/* Inner shadow for depth */
|
/* Inner shadow for depth */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1708,27 +1747,29 @@ input[type='search']::-webkit-search-cancel-button {
|
||||||
bottom: 4px;
|
bottom: 4px;
|
||||||
background-color: var(--foreground);
|
background-color: var(--foreground);
|
||||||
transition: transform var(--transition-spring, 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275));
|
transition: transform var(--transition-spring, 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275));
|
||||||
|
|
||||||
/* Spring animation */
|
/* Spring animation */
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
box-shadow: 0 2px 4px rgb(0, 0, 0, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
input:checked+.slider {
|
input:checked + .slider {
|
||||||
background-color: var(--primary);
|
background-color: var(--primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
input:checked+.slider::before {
|
input:checked + .slider::before {
|
||||||
transform: translateX(16px);
|
transform: translateX(16px);
|
||||||
background-color: var(--primary-foreground);
|
background-color: var(--primary-foreground);
|
||||||
box-shadow: -2px 2px 4px rgba(0, 0, 0, 0.1);
|
box-shadow: -2px 2px 4px rgb(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle-switch:hover .slider::before {
|
.toggle-switch:hover .slider::before {
|
||||||
transform: scale(1.1);
|
transform: scale(1.1);
|
||||||
|
|
||||||
/* Hover scale effect */
|
/* Hover scale effect */
|
||||||
}
|
}
|
||||||
|
|
||||||
input:checked+.toggle-switch:hover .slider::before {
|
input:checked + .toggle-switch:hover .slider::before {
|
||||||
transform: translateX(16px) scale(1.1);
|
transform: translateX(16px) scale(1.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1780,8 +1821,11 @@ input:checked+.toggle-switch:hover .slider::before {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: color var(--transition-fast), transform var(--transition-fast);
|
transition:
|
||||||
|
color var(--transition-fast),
|
||||||
|
transform var(--transition-fast);
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
||||||
/* Allow transform */
|
/* Allow transform */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1813,7 +1857,10 @@ input:checked+.toggle-switch:hover .slider::before {
|
||||||
border: none;
|
border: none;
|
||||||
color: var(--muted-foreground);
|
color: var(--muted-foreground);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: transform var(--transition-fast), color var(--transition-fast), background-color var(--transition-fast);
|
transition:
|
||||||
|
transform var(--transition-fast),
|
||||||
|
color var(--transition-fast),
|
||||||
|
background-color var(--transition-fast);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
@ -1826,11 +1873,13 @@ input:checked+.toggle-switch:hover .slider::before {
|
||||||
|
|
||||||
.player-controls .buttons button:hover {
|
.player-controls .buttons button:hover {
|
||||||
transform: scale(1.1);
|
transform: scale(1.1);
|
||||||
|
|
||||||
/* Pop effect */
|
/* Pop effect */
|
||||||
}
|
}
|
||||||
|
|
||||||
.player-controls .buttons button:active {
|
.player-controls .buttons button:active {
|
||||||
transform: scale(0.9);
|
transform: scale(0.9);
|
||||||
|
|
||||||
/* Press effect */
|
/* Press effect */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2088,10 +2137,14 @@ input:checked+.toggle-switch:hover .slider::before {
|
||||||
padding: 0.5rem 0.75rem;
|
padding: 0.5rem 0.75rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
transition: background-color var(--transition-fast), transform var(--transition-fast);
|
transition:
|
||||||
|
background-color var(--transition-fast),
|
||||||
|
transform var(--transition-fast);
|
||||||
|
|
||||||
/* Add transform */
|
/* Add transform */
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
/* Ensure spacing if icons are added */
|
/* Ensure spacing if icons are added */
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
@ -2100,6 +2153,7 @@ input:checked+.toggle-switch:hover .slider::before {
|
||||||
#sort-menu li:hover {
|
#sort-menu li:hover {
|
||||||
background-color: var(--secondary);
|
background-color: var(--secondary);
|
||||||
transform: translateX(4px);
|
transform: translateX(4px);
|
||||||
|
|
||||||
/* Slide interaction */
|
/* Slide interaction */
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
}
|
}
|
||||||
|
|
@ -2327,12 +2381,15 @@ input:checked+.toggle-switch:hover .slider::before {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
transition: transform var(--transition-fast), background-color var(--transition-fast);
|
transition:
|
||||||
|
transform var(--transition-fast),
|
||||||
|
background-color var(--transition-fast);
|
||||||
}
|
}
|
||||||
|
|
||||||
.fullscreen-buttons button:hover {
|
.fullscreen-buttons button:hover {
|
||||||
background: rgb(255, 255, 255, 0.1);
|
background: rgb(255, 255, 255, 0.1);
|
||||||
transform: scale(1.15) rotate(0deg);
|
transform: scale(1.15) rotate(0deg);
|
||||||
|
|
||||||
/* Slight rotation on some icons could be cool, but sticking to scale */
|
/* Slight rotation on some icons could be cool, but sticking to scale */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2610,6 +2667,7 @@ input:checked+.toggle-switch:hover .slider::before {
|
||||||
background: linear-gradient(90deg, var(--secondary) 0%, var(--muted) 50%, var(--secondary) 100%);
|
background: linear-gradient(90deg, var(--secondary) 0%, var(--muted) 50%, var(--secondary) 100%);
|
||||||
background-size: 200% 100%;
|
background-size: 200% 100%;
|
||||||
animation: skeleton-loading 2s infinite ease-in-out;
|
animation: skeleton-loading 2s infinite ease-in-out;
|
||||||
|
|
||||||
/* Slower, smoother pulse */
|
/* Slower, smoother pulse */
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
}
|
}
|
||||||
|
|
@ -2738,7 +2796,10 @@ input:checked+.toggle-switch:hover .slider::before {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
transition: transform var(--transition-fast), color var(--transition-fast), background-color var(--transition-fast);
|
transition:
|
||||||
|
transform var(--transition-fast),
|
||||||
|
color var(--transition-fast),
|
||||||
|
background-color var(--transition-fast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#api-instance-list li button:hover {
|
#api-instance-list li button:hover {
|
||||||
|
|
@ -2875,7 +2936,9 @@ input:checked+.toggle-switch:hover .slider::before {
|
||||||
.about-features li:hover {
|
.about-features li:hover {
|
||||||
color: var(--highlight);
|
color: var(--highlight);
|
||||||
transform: translateX(4px);
|
transform: translateX(4px);
|
||||||
transition: transform var(--transition-fast), color var(--transition-fast);
|
transition:
|
||||||
|
transform var(--transition-fast),
|
||||||
|
color var(--transition-fast);
|
||||||
}
|
}
|
||||||
|
|
||||||
.about-tech p {
|
.about-tech p {
|
||||||
|
|
@ -5027,7 +5090,10 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
||||||
input,
|
input,
|
||||||
select,
|
select,
|
||||||
textarea {
|
textarea {
|
||||||
transition: border-color var(--transition-fast), box-shadow var(--transition-fast), background-color var(--transition-fast);
|
transition:
|
||||||
|
border-color var(--transition-fast),
|
||||||
|
box-shadow var(--transition-fast),
|
||||||
|
background-color var(--transition-fast);
|
||||||
}
|
}
|
||||||
|
|
||||||
input:focus,
|
input:focus,
|
||||||
|
|
@ -5035,13 +5101,13 @@ select:focus,
|
||||||
textarea:focus {
|
textarea:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: var(--ring);
|
border-color: var(--ring);
|
||||||
box-shadow: 0 0 0 3px rgba(var(--highlight-rgb), 0.2);
|
box-shadow: 0 0 0 3px rgb(var(--highlight-rgb), 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Modals */
|
/* Modals */
|
||||||
.modal.active {
|
.modal.active {
|
||||||
backdrop-filter: blur(4px);
|
backdrop-filter: blur(4px);
|
||||||
background: rgba(0, 0, 0, 0.6);
|
background: rgb(0, 0, 0, 0.6);
|
||||||
transition: opacity var(--transition-normal);
|
transition: opacity var(--transition-normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5065,6 +5131,7 @@ textarea:focus {
|
||||||
.heart-icon.filled {
|
.heart-icon.filled {
|
||||||
animation: heart-beat 0.4s var(--ease-elastic);
|
animation: heart-beat 0.4s var(--ease-elastic);
|
||||||
fill: #ef4444;
|
fill: #ef4444;
|
||||||
|
|
||||||
/* Standardize heart red */
|
/* Standardize heart red */
|
||||||
stroke: #ef4444;
|
stroke: #ef4444;
|
||||||
}
|
}
|
||||||
|
|
@ -5076,10 +5143,10 @@ textarea:focus {
|
||||||
.equalizer-container {
|
.equalizer-container {
|
||||||
margin-top: var(--spacing-md);
|
margin-top: var(--spacing-md);
|
||||||
padding: var(--spacing-lg);
|
padding: var(--spacing-lg);
|
||||||
background: linear-gradient(145deg, var(--card), rgba(var(--highlight-rgb), 0.03));
|
background: linear-gradient(145deg, var(--card), rgb(var(--highlight-rgb), 0.03));
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: var(--radius-lg);
|
border-radius: var(--radius-lg);
|
||||||
box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.05);
|
box-shadow: inset 0 1px 1px rgb(255, 255, 255, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.equalizer-header {
|
.equalizer-header {
|
||||||
|
|
@ -5110,7 +5177,9 @@ textarea:focus {
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
|
transition:
|
||||||
|
border-color var(--transition-fast),
|
||||||
|
box-shadow var(--transition-fast);
|
||||||
}
|
}
|
||||||
|
|
||||||
.equalizer-preset-row select:hover {
|
.equalizer-preset-row select:hover {
|
||||||
|
|
@ -5120,7 +5189,7 @@ textarea:focus {
|
||||||
.equalizer-preset-row select:focus {
|
.equalizer-preset-row select:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: var(--ring);
|
border-color: var(--ring);
|
||||||
box-shadow: 0 0 0 3px rgba(var(--highlight-rgb), 0.2);
|
box-shadow: 0 0 0 3px rgb(var(--highlight-rgb), 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#equalizer-reset-btn {
|
#equalizer-reset-btn {
|
||||||
|
|
@ -5184,7 +5253,7 @@ textarea:focus {
|
||||||
|
|
||||||
/* Vertical slider styling */
|
/* Vertical slider styling */
|
||||||
.eq-slider {
|
.eq-slider {
|
||||||
-webkit-appearance: none;
|
appearance: none;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
writing-mode: vertical-lr;
|
writing-mode: vertical-lr;
|
||||||
direction: rtl;
|
direction: rtl;
|
||||||
|
|
@ -5214,7 +5283,7 @@ textarea:focus {
|
||||||
|
|
||||||
/* Thumb */
|
/* Thumb */
|
||||||
.eq-slider::-webkit-slider-thumb {
|
.eq-slider::-webkit-slider-thumb {
|
||||||
-webkit-appearance: none;
|
appearance: none;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
|
|
@ -5223,9 +5292,11 @@ textarea:focus {
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
margin-left: -6px;
|
margin-left: -6px;
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 2px 8px rgba(0, 0, 0, 0.3),
|
0 2px 8px rgb(0, 0, 0, 0.3),
|
||||||
inset 0 1px 2px rgba(255, 255, 255, 0.3);
|
inset 0 1px 2px rgb(255, 255, 255, 0.3);
|
||||||
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
transition:
|
||||||
|
transform 0.15s ease,
|
||||||
|
box-shadow 0.15s ease;
|
||||||
border: 2px solid var(--background);
|
border: 2px solid var(--background);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5236,24 +5307,26 @@ textarea:focus {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 2px 8px rgba(0, 0, 0, 0.3),
|
0 2px 8px rgb(0, 0, 0, 0.3),
|
||||||
inset 0 1px 2px rgba(255, 255, 255, 0.3);
|
inset 0 1px 2px rgb(255, 255, 255, 0.3);
|
||||||
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
transition:
|
||||||
|
transform 0.15s ease,
|
||||||
|
box-shadow 0.15s ease;
|
||||||
border: 2px solid var(--background);
|
border: 2px solid var(--background);
|
||||||
}
|
}
|
||||||
|
|
||||||
.eq-slider::-webkit-slider-thumb:hover {
|
.eq-slider::-webkit-slider-thumb:hover {
|
||||||
transform: scale(1.15);
|
transform: scale(1.15);
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 4px 12px rgba(var(--highlight-rgb), 0.4),
|
0 4px 12px rgb(var(--highlight-rgb), 0.4),
|
||||||
inset 0 1px 2px rgba(255, 255, 255, 0.3);
|
inset 0 1px 2px rgb(255, 255, 255, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.eq-slider::-moz-range-thumb:hover {
|
.eq-slider::-moz-range-thumb:hover {
|
||||||
transform: scale(1.15);
|
transform: scale(1.15);
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 4px 12px rgba(var(--highlight-rgb), 0.4),
|
0 4px 12px rgb(var(--highlight-rgb), 0.4),
|
||||||
inset 0 1px 2px rgba(255, 255, 255, 0.3);
|
inset 0 1px 2px rgb(255, 255, 255, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.eq-slider::-webkit-slider-thumb:active {
|
.eq-slider::-webkit-slider-thumb:active {
|
||||||
|
|
@ -5272,14 +5345,14 @@ textarea:focus {
|
||||||
|
|
||||||
.eq-slider:focus::-webkit-slider-thumb {
|
.eq-slider:focus::-webkit-slider-thumb {
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 0 0 4px rgba(var(--highlight-rgb), 0.3),
|
0 0 0 4px rgb(var(--highlight-rgb), 0.3),
|
||||||
0 2px 8px rgba(0, 0, 0, 0.3);
|
0 2px 8px rgb(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.eq-slider:focus::-moz-range-thumb {
|
.eq-slider:focus::-moz-range-thumb {
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 0 0 4px rgba(var(--highlight-rgb), 0.3),
|
0 0 0 4px rgb(var(--highlight-rgb), 0.3),
|
||||||
0 2px 8px rgba(0, 0, 0, 0.3);
|
0 2px 8px rgb(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.eq-value {
|
.eq-value {
|
||||||
|
|
@ -5291,17 +5364,19 @@ textarea:focus {
|
||||||
padding: 2px 4px;
|
padding: 2px 4px;
|
||||||
background: var(--input);
|
background: var(--input);
|
||||||
border-radius: var(--radius-sm);
|
border-radius: var(--radius-sm);
|
||||||
transition: color 0.2s ease, background 0.2s ease;
|
transition:
|
||||||
|
color 0.2s ease,
|
||||||
|
background 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.eq-value.positive {
|
.eq-value.positive {
|
||||||
color: var(--highlight);
|
color: var(--highlight);
|
||||||
background: rgba(var(--highlight-rgb), 0.15);
|
background: rgb(var(--highlight-rgb), 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.eq-value.negative {
|
.eq-value.negative {
|
||||||
color: #ef4444;
|
color: #ef4444;
|
||||||
background: rgba(239, 68, 68, 0.15);
|
background: rgb(239, 68, 68, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.eq-freq {
|
.eq-freq {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue