style: auto-fix linting issues

This commit is contained in:
JulienMaille 2026-01-16 17:37:12 +00:00 committed by Julien Maille
parent 82301e8a44
commit bae0d0a170
19 changed files with 118 additions and 205 deletions

View file

@ -19,7 +19,7 @@ export default [
},
rules: {
'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
'no-console': ['warn', { allow: ['warn', 'error'] }],
'no-console': ['warn', { allow: ['log', 'warn', 'error'] }],
},
},
];

View file

@ -152,7 +152,7 @@ export function initializeFirebaseSettingsUI() {
customFirebaseConfigContainer.classList.add('visible');
toggleFirebaseConfigBtn.textContent = 'Hide Custom Configuration';
}
} catch (e) {
} catch {
firebaseConfigInput.value = currentConfig;
}
}
@ -180,7 +180,7 @@ export function initializeFirebaseSettingsUI() {
prompt('Copy this link:', link);
});
}
} catch (e) {
} catch {
alert('Invalid configuration found.');
}
});

View file

@ -1,3 +1,4 @@
import PocketBase from 'pocketbase';
import { db } from '../db.js';
import { authManager } from './auth.js';
@ -292,7 +293,9 @@ const syncManager = {
if (typeof extraData === 'string') {
try {
extraData = JSON.parse(extraData);
} catch (e) {}
} catch {
// Ignore
}
}
if (!rawCover && extraData && typeof extraData === 'object') {

View file

@ -10,13 +10,7 @@ import {
import { UIRenderer } from './ui.js';
import { Player } from './player.js';
import { LastFMScrobbler } from './lastfm.js';
import {
LyricsManager,
openLyricsPanel,
clearLyricsPanelSync,
renderLyricsInFullscreen,
clearFullscreenLyricsSync,
} from './lyrics.js';
import { LyricsManager, openLyricsPanel, clearLyricsPanelSync } from './lyrics.js';
import { createRouter, updateTabTitle } from './router.js';
import { initializeSettings } from './settings.js';
import { initializePlayerEvents, initializeTrackInteractions, handleTrackAction } from './events.js';
@ -176,7 +170,7 @@ function showOfflineNotification() {
document.body.appendChild(notification);
setTimeout(() => {
notification.style.animation = 'slideOut 0.3s ease forwards';
notification.style.animation = 'slide-out 0.3s ease forwards';
setTimeout(() => notification.remove(), 300);
}, 5000);
}
@ -184,7 +178,7 @@ function showOfflineNotification() {
function hideOfflineNotification() {
const notification = document.querySelector('.offline-notification');
if (notification) {
notification.style.animation = 'slideOut 0.3s ease forwards';
notification.style.animation = 'slide-out 0.3s ease forwards';
setTimeout(() => notification.remove(), 300);
}
}
@ -398,7 +392,7 @@ document.addEventListener('DOMContentLoaded', async () => {
if (!userPlaylist) {
try {
userPlaylist = await syncManager.getPublicPlaylist(playlistId);
} catch (e) {
} catch {
// Not a public playlist
}
}
@ -461,7 +455,7 @@ document.addEventListener('DOMContentLoaded', async () => {
} else {
try {
await syncManager.unpublishPlaylist(playlist.id);
} catch (e) {
} catch {
// Ignore error if it wasn't public
}
}
@ -1292,7 +1286,7 @@ async function parseCSV(csvText, api, onProgress) {
const cleanTitle = (t) =>
t
.split(' - ')[0]
.replace(/\s*[\(\[]feat\.?.*?[\)\]]/i, '')
.replace(/\s*[([]feat\.?.*?[)\]]/i, '')
.trim();
const cleanedTitle = cleanTitle(trackTitle);
const isTitleCleaned = cleanedTitle !== trackTitle;

View file

@ -57,7 +57,7 @@ export class APICache {
return cached.data;
}
} catch (error) {
console.debug('IndexedDB read error:', error);
console.log('IndexedDB read error:', error);
}
}
@ -83,7 +83,7 @@ export class APICache {
try {
await this.setInIndexedDB(entry);
} catch (error) {
console.debug('IndexedDB write error:', error);
console.log('IndexedDB write error:', error);
}
}
}
@ -163,7 +163,7 @@ export class APICache {
}
};
} catch (error) {
console.debug('Failed to clear expired IndexedDB entries:', error);
console.log('Failed to clear expired IndexedDB entries:', error);
}
}
}

View file

@ -136,7 +136,7 @@ export class MusicDatabase {
try {
const result = await this.performTransaction(storeName, 'readonly', (store) => store.get(id));
return !!result;
} catch (e) {
} catch {
return false;
}
}
@ -316,12 +316,10 @@ export class MusicDatabase {
return new Promise((resolve, reject) => {
const transaction = db.transaction(storeName, 'readwrite');
const store = transaction.objectStore(storeName);
let hasChanges = false;
// force clear on first sync
console.log(`Clearing ${storeName} to Make Sure Everythings Good`);
store.clear();
hasChanges = true;
itemsArray.forEach((item) => {
if (item.id && typeof item.id === 'string' && !isNaN(item.id)) {

View file

@ -64,7 +64,7 @@ export function showNotification(message) {
// Auto remove
setTimeout(() => {
notifEl.style.animation = 'slideOut 0.3s ease';
notifEl.style.animation = 'slide-out 0.3s ease forwards';
setTimeout(() => notifEl.remove(), 300);
}, 1500);
}
@ -162,7 +162,7 @@ function removeDownloadTask(trackId) {
if (!task) return;
const { taskEl } = task;
taskEl.style.animation = 'slideOut 0.3s ease';
taskEl.style.animation = 'slide-out 0.3s ease forwards';
setTimeout(() => {
taskEl.remove();
@ -179,7 +179,7 @@ function removeBulkDownloadTask(notifEl) {
const task = bulkDownloadTasks.get(notifEl);
if (!task) return;
notifEl.style.animation = 'slideOut 0.3s ease';
notifEl.style.animation = 'slide-out 0.3s ease forwards';
setTimeout(() => {
notifEl.remove();
@ -225,6 +225,7 @@ async function downloadTrackBlob(track, quality, api, lyricsManager = null, sign
}
// Handle DASH streams (blob URLs)
let blob;
if (streamUrl.startsWith('blob:')) {
try {
const downloader = new DashDownloader();
@ -266,7 +267,7 @@ async function generateAndDownloadZip(zip, filename, notification, progressTotal
compression: 'STORE',
streamFiles: true,
})
.on('data', (chunk, metadata) => {
.on('data', (chunk) => {
writable.write(chunk);
})
.on('error', (err) => {
@ -364,7 +365,7 @@ async function downloadTracksToZip(
zip.file(`${folderName}/${lrcFilename}`, lrcContent);
}
}
} catch (error) {
} catch {
console.log('Could not add lyrics for:', trackTitle);
}
}
@ -518,7 +519,7 @@ export async function downloadDiscography(artist, selectedReleases, api, quality
zip.file(`${fullFolderPath}/${lrcFilename}`, lrcContent);
}
}
} catch (error) {
} catch {
// Silent fail for lyrics in bulk
}
}
@ -547,7 +548,7 @@ export async function downloadDiscography(artist, selectedReleases, api, quality
}
}
function createBulkDownloadNotification(type, name, totalItems) {
function createBulkDownloadNotification(type, name, _totalItems) {
const container = createDownloadNotification();
const notifEl = document.createElement('div');
@ -608,7 +609,7 @@ function completeBulkDownload(notifEl, success = true, message = null) {
statusEl.style.color = '#10b981';
setTimeout(() => {
notifEl.style.animation = 'slideOut 0.3s ease';
notifEl.style.animation = 'slide-out 0.3s ease forwards';
setTimeout(() => notifEl.remove(), 300);
}, 3000);
} else {
@ -617,7 +618,7 @@ function completeBulkDownload(notifEl, success = true, message = null) {
statusEl.style.color = '#ef4444';
setTimeout(() => {
notifEl.style.animation = 'slideOut 0.3s ease';
notifEl.style.animation = 'slide-out 0.3s ease forwards';
setTimeout(() => notifEl.remove(), 300);
}, 5000);
}
@ -660,7 +661,7 @@ export async function downloadTrackWithMetadata(track, quality, api, lyricsManag
ongoingDownloads.add(downloadKey);
try {
const { taskEl } = addDownloadTask(track.id, enrichedTrack, filename, api, controller);
addDownloadTask(track.id, enrichedTrack, filename, api, controller);
await api.downloadTrack(track.id, quality, filename, {
signal: controller.signal,
@ -678,7 +679,7 @@ export async function downloadTrackWithMetadata(track, quality, api, lyricsManag
if (lyricsData) {
lyricsManager.downloadLRC(lyricsData, track);
}
} catch (error) {
} catch {
console.log('Could not download lyrics for track');
}
}

View file

@ -1,25 +1,13 @@
//js/events.js
import {
SVG_PLAY,
SVG_PAUSE,
SVG_VOLUME,
SVG_MUTE,
REPEAT_MODE,
trackDataStore,
RATE_LIMIT_ERROR_MESSAGE,
buildTrackFilename,
getTrackTitle,
formatTime,
} from './utils.js';
import { SVG_PLAY, SVG_PAUSE, SVG_VOLUME, SVG_MUTE, REPEAT_MODE, trackDataStore, formatTime } from './utils.js';
import { lastFMStorage, waveformSettings } from './storage.js';
import { showNotification, downloadTrackWithMetadata } from './downloads.js';
import { lyricsSettings, downloadQualitySettings } from './storage.js';
import { downloadQualitySettings } from './storage.js';
import { updateTabTitle } from './router.js';
import { db } from './db.js';
import { syncManager } from './accounts/pocketbase.js';
import { waveformGenerator } from './waveform.js';
let currentWaveformPeaks = null;
let currentTrackIdForWaveform = null;
export function initializePlayerEvents(player, audioPlayer, scrobbler, ui) {
@ -396,7 +384,7 @@ function initializeSmoothSliders(audioPlayer, player) {
}
});
document.addEventListener('mouseup', (e) => {
document.addEventListener('mouseup', () => {
if (isSeeking) {
// Commit the seek
if (!isNaN(audioPlayer.duration)) {
@ -412,7 +400,7 @@ function initializeSmoothSliders(audioPlayer, player) {
}
});
document.addEventListener('touchend', (e) => {
document.addEventListener('touchend', () => {
if (isSeeking) {
if (!isNaN(audioPlayer.duration)) {
audioPlayer.currentTime = lastSeekPosition * audioPlayer.duration;
@ -562,7 +550,7 @@ export async function handleTrackAction(
if (!playlist) {
try {
playlist = await syncManager.getPublicPlaylist(item.id);
} catch (e) {
} catch {
// Ignore
}
}

View file

@ -1,5 +1,4 @@
//js/lastfm.js
import { delay, getTrackArtists } from './utils.js';
export class LastFMScrobbler {
constructor() {
@ -66,7 +65,7 @@ export class LastFMScrobbler {
try {
const { default: md5 } = await import('https://cdn.jsdelivr.net/npm/md5@2.3.0/+esm');
return md5(signatureString);
} catch (e) {
} catch {
console.error('MD5 library not available');
throw new Error('MD5 library required for Last.fm');
}

View file

@ -1,10 +1,9 @@
//js/lyrics.js
import { getTrackTitle, getTrackArtists, buildTrackFilename, SVG_DOWNLOAD, SVG_CLOSE } from './utils.js';
import { getTrackTitle, getTrackArtists, buildTrackFilename, SVG_CLOSE } from './utils.js';
import { sidePanelManager } from './side-panel.js';
// Dictionary path for kuromoji
// Using CDN - the kuroshiro-analyzer loaded from unpkg will use this as base for fetching dict files
const KUROMOJI_DICT_PATH = 'https://cdn.jsdelivr.net/npm/kuromoji@0.1.2/dict/';
export class LyricsManager {
constructor(api) {
@ -190,7 +189,7 @@ export class LyricsManager {
getRomajiMode() {
try {
return localStorage.getItem('lyricsRomajiMode') === 'true';
} catch (e) {
} catch {
return false;
}
}
@ -549,7 +548,7 @@ export async function openLyricsPanel(track, audioPlayer, lyricsManager) {
romajiBtn.addEventListener('click', async () => {
const amLyrics = sidePanelManager.panel.querySelector('am-lyrics');
if (amLyrics) {
const newMode = await manager.toggleRomajiMode(amLyrics);
await manager.toggleRomajiMode(amLyrics);
updateRomajiBtn();
}
});

View file

@ -243,7 +243,6 @@ async function readMp3Metadata(file, metadata) {
if (file.size > 128) {
const tailBuffer = await file.slice(file.size - 128).arrayBuffer();
const tailView = new DataView(tailBuffer);
const tag = new TextDecoder().decode(new Uint8Array(tailBuffer, 0, 3));
if (tag === 'TAG') {
const title = new TextDecoder()
@ -288,33 +287,6 @@ function readID3Text(view) {
return decoder.decode(buffer).replace(/\0/g, '');
}
function readID3Picture(view) {
let offset = 1;
const encoding = view.getUint8(0);
let mimeEnd = offset;
while (view.getUint8(mimeEnd) !== 0) mimeEnd++;
const mime = new TextDecoder('iso-8859-1').decode(
view.buffer.slice(view.byteOffset + offset, view.byteOffset + mimeEnd)
);
offset = mimeEnd + 1;
const picType = view.getUint8(offset);
offset++;
let descEnd = offset;
while (
view.getUint8(descEnd) !== 0 ||
(encoding === 1 || encoding === 2 ? view.getUint8(descEnd + 1) !== 0 : false)
)
descEnd++;
offset = descEnd + (encoding === 1 || encoding === 2 ? 2 : 1);
const imgData = view.buffer.slice(view.byteOffset + offset, view.byteOffset + view.byteLength);
const blob = new Blob([imgData], { type: mime });
return URL.createObjectURL(blob);
}
/**
* Adds Vorbis comment metadata to FLAC files
*/
@ -438,7 +410,7 @@ function createVorbisCommentBlock(track) {
if (!isNaN(year)) {
comments.push(['DATE', String(year)]);
}
} catch (error) {
} catch {
// Invalid date, skip
}
}
@ -787,7 +759,7 @@ function createMp4MetadataAtoms(track) {
if (!isNaN(year)) {
tags['©day'] = String(year);
}
} catch (error) {
} catch {
// Invalid date, skip
}
}
@ -862,12 +834,6 @@ function rebuildMp4WithMetadata(dataView, atoms, metadataAtoms) {
// Write preserved children of moov
for (const child of filteredMoovChildren) {
const childStart = moovAtom.offset + 8 + child.offset; // child.offset is relative to moov body start in our parseMp4Atoms helper usage?
// Wait, parseMp4Atoms returns absolute offsets usually?
// Let's verify parseMp4Atoms usage.
// When we passed a slice DataView, the offsets returned by parseMp4Atoms
// are relative to the start of that DataView (which is moov body start).
const absoluteChildStart = moovAtom.offset + 8 + child.offset;
newFile.set(originalArray.subarray(absoluteChildStart, absoluteChildStart + child.size), offset);
offset += child.size;

View file

@ -618,7 +618,7 @@ export class Player {
position: Math.min(this.audio.currentTime, duration),
});
} catch (error) {
console.debug('Failed to update Media Session position:', error);
console.log('Failed to update Media Session position:', error);
}
}

View file

@ -58,7 +58,7 @@ export function initializeSettings(scrobbler, player, api, ui) {
authButtonsContainer.style.display = 'flex';
emailInput.value = '';
passwordInput.value = '';
} catch (e) {
} catch {
// Error handled in authManager
}
});
@ -78,7 +78,7 @@ export function initializeSettings(scrobbler, player, api, ui) {
authButtonsContainer.style.display = 'flex';
emailInput.value = '';
passwordInput.value = '';
} catch (e) {
} catch {
// Error handled in authManager
}
});
@ -165,7 +165,7 @@ export function initializeSettings(scrobbler, player, api, ui) {
lastfmToggle.checked = true;
alert(`Successfully connected to Last.fm as ${result.username}!`);
}
} catch (e) {
} catch {
// Still waiting
}
}, 2000);

View file

@ -1,4 +1,5 @@
//js/smooth-scrolling.js
/* global Lenis */
import { smoothScrollingSettings } from './storage.js';
let lenis = null;

View file

@ -31,7 +31,7 @@ export const apiSettings = {
if (isSimpleArray) {
groupedInstances.api = [...data.api];
} else {
for (const [provider, config] of Object.entries(data.api)) {
for (const [, config] of Object.entries(data.api)) {
if (config.cors === false && Array.isArray(config.urls)) {
groupedInstances.api.push(...config.urls);
}
@ -122,7 +122,7 @@ export const apiSettings = {
}
return data;
} catch (e) {
} catch {
return { speeds: {}, timestamp: Date.now() };
}
},
@ -141,7 +141,7 @@ export const apiSettings = {
try {
localStorage.setItem(this.SPEED_TEST_CACHE_KEY, JSON.stringify(currentCache));
} catch (e) {
} catch {
console.warn('[SpeedTest] Failed to cache results');
}
@ -253,7 +253,7 @@ export const recentActivityManager = {
if (!parsed.playlists) parsed.playlists = [];
if (!parsed.mixes) parsed.mixes = [];
return parsed;
} catch (e) {
} catch {
return { artists: [], albums: [], playlists: [], mixes: [] };
}
},
@ -311,7 +311,7 @@ export const themeManager = {
getTheme() {
try {
return localStorage.getItem(this.STORAGE_KEY) || 'system';
} catch (e) {
} catch {
return 'system';
}
},
@ -343,7 +343,7 @@ export const themeManager = {
try {
const stored = localStorage.getItem(this.CUSTOM_THEME_KEY);
return stored ? JSON.parse(stored) : null;
} catch (e) {
} catch {
return null;
}
},
@ -363,13 +363,10 @@ export const themeManager = {
};
export const lastFMStorage = {
STORAGE_KEY: 'lastfm-enabled',
LOVE_ON_LIKE_KEY: 'lastfm-love-on-like',
isEnabled() {
try {
return localStorage.getItem(this.STORAGE_KEY) === 'true';
} catch (e) {
} catch {
return false;
}
},
@ -381,7 +378,7 @@ export const lastFMStorage = {
shouldLoveOnLike() {
try {
return localStorage.getItem(this.LOVE_ON_LIKE_KEY) === 'true';
} catch (e) {
} catch {
return false;
}
},
@ -397,7 +394,7 @@ export const nowPlayingSettings = {
getMode() {
try {
return localStorage.getItem(this.STORAGE_KEY) || 'cover';
} catch (e) {
} catch {
return 'cover';
}
},
@ -413,7 +410,7 @@ export const lyricsSettings = {
shouldDownloadLyrics() {
try {
return localStorage.getItem(this.DOWNLOAD_WITH_TRACKS) === 'true';
} catch (e) {
} catch {
return false;
}
},
@ -430,7 +427,7 @@ export const backgroundSettings = {
try {
// Default to true if not set
return localStorage.getItem(this.STORAGE_KEY) !== 'false';
} catch (e) {
} catch {
return true;
}
},
@ -448,7 +445,7 @@ export const trackListSettings = {
const mode = localStorage.getItem(this.STORAGE_KEY) || 'dropdown';
document.documentElement.setAttribute('data-track-actions-mode', mode);
return mode;
} catch (e) {
} catch {
return 'dropdown';
}
},
@ -467,7 +464,7 @@ export const cardSettings = {
try {
const val = localStorage.getItem(this.COMPACT_ARTIST_KEY);
return val === null ? true : val === 'true';
} catch (e) {
} catch {
return true;
}
},
@ -479,7 +476,7 @@ export const cardSettings = {
isCompactAlbum() {
try {
return localStorage.getItem(this.COMPACT_ALBUM_KEY) === 'true';
} catch (e) {
} catch {
return false;
}
},
@ -512,7 +509,7 @@ export const downloadQualitySettings = {
getQuality() {
try {
return localStorage.getItem(this.STORAGE_KEY) || 'LOSSLESS';
} catch (e) {
} catch {
return 'LOSSLESS';
}
},
@ -527,7 +524,7 @@ export const waveformSettings = {
isEnabled() {
try {
return localStorage.getItem(this.STORAGE_KEY) === 'true';
} catch (e) {
} catch {
return false;
}
},
@ -543,7 +540,7 @@ export const smoothScrollingSettings = {
isEnabled() {
try {
return localStorage.getItem(this.STORAGE_KEY) === 'true';
} catch (e) {
} catch {
return false;
}
},
@ -560,7 +557,7 @@ export const queueManager = {
try {
const data = localStorage.getItem(this.STORAGE_KEY);
return data ? JSON.parse(data) : null;
} catch (e) {
} catch {
return null;
}
},

View file

@ -5,7 +5,6 @@ import {
SVG_HEART,
SVG_DOWNLOAD,
formatTime,
trackDataStore,
getTrackTitle,
getTrackArtists,
escapeHtml,
@ -158,7 +157,7 @@ export function initializeUIInteractions(player, api) {
try {
let addedCount = 0;
for (const track of currentQueue) {
const playlist = await db.addTrackToPlaylist(playlistId, track);
await db.addTrackToPlaylist(playlistId, track);
addedCount++;
}
@ -302,7 +301,6 @@ export function initializeUIInteractions(player, api) {
trackMixItem.style.display = hasMix ? 'block' : 'none';
}
const rect = item.getBoundingClientRect();
const menuWidth = 150;
const menuHeight = 200;
@ -325,7 +323,7 @@ export function initializeUIInteractions(player, api) {
}
});
item.addEventListener('dragstart', (e) => {
item.addEventListener('dragstart', () => {
draggedQueueIndex = index;
item.style.opacity = '0.5';
});

View file

@ -15,8 +15,9 @@ import {
escapeHtml,
} from './utils.js';
import { openLyricsPanel } from './lyrics.js';
import { recentActivityManager, backgroundSettings, trackListSettings, cardSettings } from './storage.js';
import { recentActivityManager, backgroundSettings, cardSettings } from './storage.js';
import { db } from './db.js';
import { showNotification } from './downloads.js';
import { getVibrantColorFromImage } from './vibrant-color.js';
import { syncManager } from './accounts/pocketbase.js';
@ -68,7 +69,7 @@ export class UIRenderer {
this.vibrantColorCache.set(url, null);
this.resetVibrantColor();
}
} catch (e) {
} catch {
this.vibrantColorCache.set(url, null);
this.resetVibrantColor();
}
@ -161,7 +162,6 @@ export class UIRenderer {
}
createTrackItemHTML(track, index, showCover = false, hasMultipleDiscs = false) {
const playIconSmall = SVG_PLAY;
const trackImageHTML = showCover
? `<img src="${this.api.getCoverUrl(track.album?.cover)}" alt="Track Cover" class="track-item-cover" loading="lazy">`
: '';
@ -625,7 +625,6 @@ export class UIRenderer {
const title = document.getElementById('fullscreen-track-title');
const artist = document.getElementById('fullscreen-track-artist');
const nextTrackEl = document.getElementById('fullscreen-next-track');
const lyricsContainer = document.getElementById('fullscreen-lyrics-container');
const lyricsToggleBtn = document.getElementById('toggle-fullscreen-lyrics-btn');
const coverUrl = this.api.getCoverUrl(track.album?.cover, '1280');

View file

@ -288,7 +288,7 @@ export async function getCoverBlob(api, coverId) {
return blob;
}
}
} catch (e) {
} catch {
// Network error (CORS rejection not handled by SW), try proxy
const url = api.getCoverUrl(coverId, '1280');
const blob = await fetchWithProxy(url);

View file

@ -1,3 +1,4 @@
/* stylelint-disable no-descending-specificity */
:root {
color-scheme: light dark;
@ -14,6 +15,8 @@
--shadow-lg: 0 10px 30px rgb(0, 0, 0, 0.5);
--shadow-xl: 0 20px 60px rgb(0, 0, 0, 0.8);
--cover-filter: blur(50px) brightness(0.4);
--player-bar-height-desktop: 90px;
--player-bar-height-mobile: 130px;
}
:root[data-theme='monochrome'] {
@ -408,6 +411,17 @@ kbd {
cursor: pointer;
}
.search-bar svg {
position: absolute;
left: 0.75rem;
top: 50%;
transform: translateY(-50%);
color: var(--muted-foreground);
width: 20px;
height: 20px;
pointer-events: none;
}
.sidebar-nav .nav-item a:hover {
background-color: var(--secondary);
color: var(--foreground);
@ -489,19 +503,11 @@ kbd {
.search-bar {
position: relative;
width: 100%;
max-width: 400px;
}
.search-bar svg {
position: absolute;
left: 0.75rem;
top: 50%;
transform: translateY(-50%);
color: var(--muted-foreground);
width: 20px;
height: 20px;
pointer-events: none;
width: 80%;
max-width: 100%;
margin-bottom: var(--spacing-xl);
display: flex;
align-items: center;
}
.search-bar input {
@ -534,10 +540,10 @@ body.has-page-background .track-item:hover {
.page.active {
display: block;
animation: fadeIn 0.25s cubic-bezier(0.4, 0, 0.2, 1);
animation: fade-in 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
@keyframes fadeIn {
@keyframes fade-in {
from {
opacity: 0;
transform: translateY(4px);
@ -549,7 +555,7 @@ body.has-page-background .track-item:hover {
}
}
@keyframes scaleIn {
@keyframes scale-in {
from {
opacity: 0;
transform: scale(0.95);
@ -561,7 +567,7 @@ body.has-page-background .track-item:hover {
}
}
@keyframes slideIn {
@keyframes slide-in {
from {
opacity: 0;
transform: translateX(100%);
@ -573,7 +579,7 @@ body.has-page-background .track-item:hover {
}
}
@keyframes slideOut {
@keyframes slide-out {
from {
opacity: 1;
transform: translateX(0);
@ -1000,9 +1006,11 @@ body.has-page-background .track-item:hover {
display: flex;
}
.track-item:hover .track-menu-btn {
opacity: 1;
}
.track-item:hover .track-menu-btn {
opacity: 1;
padding: 0.5rem;
margin: 0;
}
.track-menu-btn:hover {
background-color: rgb(var(--highlight-rgb), 0.2);
@ -1087,7 +1095,7 @@ body.has-page-background .track-item:hover {
align-items: center;
gap: 1rem;
flex-wrap: wrap;
word-break: break-word;
overflow-wrap: break-word;
}
.detail-header-info .title.long-title {
@ -1547,9 +1555,10 @@ input:checked + .slider::before {
.volume-controls {
display: flex;
justify-content: flex-end;
align-items: center;
gap: 0.75rem;
justify-content: center !important;
align-items: flex-end !important;
gap: 0.5rem !important;
flex-direction: column !important;
}
.volume-controls button {
@ -1721,15 +1730,13 @@ input:checked + .slider::before {
.fullscreen-cover-content {
display: flex;
flex-direction: column;
flex-direction: row;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
/* Remove fixed padding to allow flex centering to work within the overlay's padded box */
padding: 1rem;
position: relative;
padding: 1rem;
}
#close-fullscreen-cover-btn {
@ -1781,7 +1788,7 @@ input:checked + .slider::before {
font-weight: 700;
margin-bottom: 0.5rem;
color: var(--foreground);
word-break: break-word;
overflow-wrap: break-word;
}
#fullscreen-track-artist {
@ -1825,7 +1832,7 @@ input:checked + .slider::before {
display: flex;
flex-direction: column;
box-shadow: var(--shadow-xl);
animation: scaleIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);
animation: scale-in 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
#queue-modal-header {
@ -2317,7 +2324,7 @@ input:checked + .slider::before {
border-radius: var(--radius);
padding: 1rem;
box-shadow: var(--shadow-lg);
animation: slideIn 0.3s ease;
animation: slide-in 0.3s ease;
min-width: 300px;
}
@ -2419,7 +2426,7 @@ input:checked + .slider::before {
align-items: center;
gap: 1rem;
max-width: 350px;
animation: slideIn 0.3s ease;
animation: slide-in 0.3s ease;
}
.offline-notification svg {
@ -2511,11 +2518,6 @@ input:checked + .slider::before {
}
/* Side Panels (Lyrics & Queue) */
:root {
--player-bar-height-desktop: 90px;
--player-bar-height-mobile: 130px;
}
.side-panel {
position: fixed;
right: 0;
@ -2756,12 +2758,6 @@ input:checked + .slider::before {
}
/* Updated Volume Controls Layout */
.volume-controls {
flex-direction: column !important;
align-items: flex-end !important;
gap: 0.5rem !important;
justify-content: center !important;
}
.player-actions-row {
display: flex;
@ -2864,21 +2860,6 @@ img[src=''] {
padding: 1rem 0;
}
.search-bar {
display: flex;
align-items: center;
width: 80%;
max-width: 100%;
}
.fullscreen-cover-content {
display: flex;
flex-direction: row;
width: 100%;
height: 100%;
position: relative;
}
.fullscreen-main-view {
flex: 1;
display: flex;
@ -2945,7 +2926,7 @@ img[src=''] {
max-width: 400px;
width: 90%;
box-shadow: var(--shadow-xl);
animation: scaleIn 0.2s ease;
animation: scale-in 0.2s ease;
max-height: 90vh;
overflow-y: auto;
}
@ -3013,7 +2994,7 @@ img[src=''] {
text-align: center;
}
@keyframes scaleIn {
@keyframes scale-in {
from {
transform: scale(0.95);
opacity: 0;
@ -3027,13 +3008,13 @@ img[src=''] {
#playlist-modal {
opacity: 1;
animation-name: fadeInOpacity;
animation-name: fade-in-opacity;
animation-iteration-count: 1;
animation-timing-function: ease-in;
animation-duration: 0.1s;
}
@keyframes fadeInOpacity {
@keyframes fade-in-opacity {
0% {
opacity: 0;
}
@ -3056,7 +3037,7 @@ img[src=''] {
z-index: 10001;
max-width: 400px;
min-width: 350px;
animation: slideIn 0.3s ease;
animation: slide-in 0.3s ease;
}
.csv-import-progress .progress-header {
@ -3349,6 +3330,9 @@ img[src=''] {
@media (max-width: 768px) {
.player-controls .progress-container {
order: -1;
max-width: none;
font-size: 0.75rem;
gap: 0.5rem;
}
#fullscreen-cover-overlay {
@ -3556,12 +3540,6 @@ img[src=''] {
height: 32px;
}
.player-controls .progress-container {
max-width: none;
font-size: 0.75rem;
gap: 0.5rem;
}
.desktop-only {
display: none !important;
}
@ -3632,11 +3610,6 @@ img[src=''] {
white-space: nowrap;
}
.track-menu-btn {
padding: 0.5rem;
margin: 0;
}
.track-menu-btn svg {
width: 18px;
height: 18px;
@ -3776,10 +3749,6 @@ img[src=''] {
.mobile-only {
display: flex !important;
}
.desktop-only {
display: none !important;
}
}
@media (max-width: 480px) {
@ -3922,6 +3891,7 @@ img[src=''] {
}
}
/* stylelint-disable-next-line media-feature-name-value-no-unknown */
@media (display-mode: window-controls-overlay) {
.app-container {
margin-top: env(titlebar-area-height, 0);