refactor, better compact cards
This commit is contained in:
parent
a880fe7777
commit
72d27ef7fe
2 changed files with 218 additions and 148 deletions
219
js/ui.js
219
js/ui.js
|
|
@ -202,55 +202,80 @@ export class UIRenderer {
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
createPlaylistCardHTML(playlist) {
|
createBaseCardHTML({ type, id, href, title, subtitle, imageHTML, actionButtonsHTML, isCompact, extraClasses = '' }) {
|
||||||
const imageId = playlist.squareImage || playlist.image || playlist.uuid; // Fallback or use a specific cover getter if needed
|
const playBtnHTML = type !== 'artist' ? `
|
||||||
const isCompact = cardSettings.isCompactAlbum();
|
<button class="play-btn card-play-btn" data-action="play-card" data-type="${type}" data-id="${id}" title="Play">
|
||||||
|
${SVG_PLAY}
|
||||||
|
</button>
|
||||||
|
` : '';
|
||||||
|
|
||||||
|
const cardContent = type === 'artist'
|
||||||
|
? `<h4 class="card-title">${title}</h4>`
|
||||||
|
: `<div class="card-info">
|
||||||
|
<h4 class="card-title">${title}</h4>
|
||||||
|
<p class="card-subtitle">${subtitle}</p>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
// In compact mode, move the play button outside the wrapper to position it on the right side of the card
|
||||||
|
const buttonsInWrapper = !isCompact ? playBtnHTML : '';
|
||||||
|
const buttonsOutside = isCompact ? playBtnHTML : '';
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="card ${isCompact ? 'compact' : ''}" data-playlist-id="${playlist.uuid}" data-href="#playlist/${playlist.uuid}" style="cursor: pointer;">
|
<div class="card ${extraClasses} ${isCompact ? 'compact' : ''}" data-${type}-id="${id}" data-href="${href}" style="cursor: pointer;">
|
||||||
<div class="card-image-wrapper">
|
<div class="card-image-wrapper">
|
||||||
<img src="${this.api.getCoverUrl(imageId)}" alt="${playlist.title}" class="card-image" loading="lazy">
|
${imageHTML}
|
||||||
<button class="like-btn card-like-btn" data-action="toggle-like" data-type="playlist" title="Add to Liked">
|
${actionButtonsHTML}
|
||||||
${this.createHeartIcon(false)}
|
${buttonsInWrapper}
|
||||||
</button>
|
|
||||||
<button class="play-btn card-play-btn" data-action="play-card" data-type="playlist" data-id="${playlist.uuid}" title="Play">
|
|
||||||
${SVG_PLAY}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="card-info">
|
|
||||||
<h4 class="card-title">${playlist.title}</h4>
|
|
||||||
<p class="card-subtitle">${playlist.numberOfTracks || 0} tracks</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
${cardContent}
|
||||||
|
${buttonsOutside}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createPlaylistCardHTML(playlist) {
|
||||||
|
const imageId = playlist.squareImage || playlist.image || playlist.uuid;
|
||||||
|
const isCompact = cardSettings.isCompactAlbum();
|
||||||
|
|
||||||
|
return this.createBaseCardHTML({
|
||||||
|
type: 'playlist',
|
||||||
|
id: playlist.uuid,
|
||||||
|
href: `#playlist/${playlist.uuid}`,
|
||||||
|
title: playlist.title,
|
||||||
|
subtitle: `${playlist.numberOfTracks || 0} tracks`,
|
||||||
|
imageHTML: `<img src="${this.api.getCoverUrl(imageId)}" alt="${playlist.title}" class="card-image" loading="lazy">`,
|
||||||
|
actionButtonsHTML: `
|
||||||
|
<button class="like-btn card-like-btn" data-action="toggle-like" data-type="playlist" title="Add to Liked">
|
||||||
|
${this.createHeartIcon(false)}
|
||||||
|
</button>
|
||||||
|
`,
|
||||||
|
isCompact
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
createMixCardHTML(mix) {
|
createMixCardHTML(mix) {
|
||||||
const imageSrc = mix.cover || 'assets/appicon.png';
|
const imageSrc = mix.cover || 'assets/appicon.png';
|
||||||
const description = mix.subTitle || mix.description || '';
|
const description = mix.subTitle || mix.description || '';
|
||||||
const isCompact = cardSettings.isCompactAlbum();
|
const isCompact = cardSettings.isCompactAlbum();
|
||||||
|
|
||||||
return `
|
return this.createBaseCardHTML({
|
||||||
<div class="card ${isCompact ? 'compact' : ''}" data-mix-id="${mix.id}" data-href="#mix/${mix.id}" style="cursor: pointer;">
|
type: 'mix',
|
||||||
<div class="card-image-wrapper">
|
id: mix.id,
|
||||||
<img src="${imageSrc}" alt="${mix.title}" class="card-image" loading="lazy">
|
href: `#mix/${mix.id}`,
|
||||||
<button class="like-btn card-like-btn" data-action="toggle-like" data-type="mix" title="Add to Liked">
|
title: mix.title,
|
||||||
${this.createHeartIcon(false)}
|
subtitle: description,
|
||||||
</button>
|
imageHTML: `<img src="${imageSrc}" alt="${mix.title}" class="card-image" loading="lazy">`,
|
||||||
<button class="play-btn card-play-btn" data-action="play-card" data-type="mix" data-id="${mix.id}" title="Play">
|
actionButtonsHTML: `
|
||||||
${SVG_PLAY}
|
<button class="like-btn card-like-btn" data-action="toggle-like" data-type="mix" title="Add to Liked">
|
||||||
</button>
|
${this.createHeartIcon(false)}
|
||||||
</div>
|
</button>
|
||||||
<div class="card-info">
|
`,
|
||||||
<h4 class="card-title">${mix.title}</h4>
|
isCompact
|
||||||
<p class="card-subtitle">${description}</p>
|
});
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createUserPlaylistCardHTML(playlist) {
|
createUserPlaylistCardHTML(playlist) {
|
||||||
let imageHTML = '';
|
let imageHTML = '';
|
||||||
|
|
||||||
if (playlist.cover) {
|
if (playlist.cover) {
|
||||||
imageHTML = `<img src="${playlist.cover}" alt="${playlist.name}" class="card-image" loading="lazy">`;
|
imageHTML = `<img src="${playlist.cover}" alt="${playlist.name}" class="card-image" loading="lazy">`;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -273,7 +298,6 @@ export class UIRenderer {
|
||||||
const count = Math.min(uniqueCovers.length, 4);
|
const count = Math.min(uniqueCovers.length, 4);
|
||||||
const itemsClass = count < 4 ? `items-${count}` : '';
|
const itemsClass = count < 4 ? `items-${count}` : '';
|
||||||
const covers = uniqueCovers.slice(0, 4);
|
const covers = uniqueCovers.slice(0, 4);
|
||||||
|
|
||||||
imageHTML = `
|
imageHTML = `
|
||||||
<div class="card-image card-collage ${itemsClass}">
|
<div class="card-image card-collage ${itemsClass}">
|
||||||
${covers.map(cover => `<img src="${this.api.getCoverUrl(cover)}" alt="" loading="lazy">`).join('')}
|
${covers.map(cover => `<img src="${this.api.getCoverUrl(cover)}" alt="" loading="lazy">`).join('')}
|
||||||
|
|
@ -288,35 +312,34 @@ export class UIRenderer {
|
||||||
|
|
||||||
const isCompact = cardSettings.isCompactAlbum();
|
const isCompact = cardSettings.isCompactAlbum();
|
||||||
|
|
||||||
return `
|
return this.createBaseCardHTML({
|
||||||
<div class="card user-playlist ${isCompact ? 'compact' : ''}" data-playlist-id="${playlist.id}" data-href="#userplaylist/${playlist.id}" style="cursor: pointer;">
|
type: 'user-playlist', // Note: data-type logic in base might need adjustment if it uses this for buttons.
|
||||||
<div class="card-image-wrapper">
|
// Actually Base uses type for data attributes. play-card uses data-type="user-playlist" which is correct.
|
||||||
${imageHTML}
|
id: playlist.id,
|
||||||
<button class="edit-playlist-btn" data-action="edit-playlist" title="Edit Playlist">
|
href: `#userplaylist/${playlist.id}`,
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
title: playlist.name,
|
||||||
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
|
subtitle: `${playlist.tracks ? playlist.tracks.length : (playlist.numberOfTracks || 0)} tracks`,
|
||||||
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
imageHTML: imageHTML,
|
||||||
</svg>
|
actionButtonsHTML: `
|
||||||
</button>
|
<button class="edit-playlist-btn" data-action="edit-playlist" title="Edit Playlist">
|
||||||
<button class="delete-playlist-btn" data-action="delete-playlist" title="Delete Playlist">
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
|
||||||
<path d="M3 6h18"/>
|
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
||||||
<path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/>
|
</svg>
|
||||||
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/>
|
</button>
|
||||||
<line x1="10" y1="11" x2="10" y2="17"/>
|
<button class="delete-playlist-btn" data-action="delete-playlist" title="Delete Playlist">
|
||||||
<line x1="14" y1="11" x2="14" y2="17"/>
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
</svg>
|
<path d="M3 6h18"/>
|
||||||
</button>
|
<path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/>
|
||||||
<button class="play-btn card-play-btn" data-action="play-card" data-type="user-playlist" data-id="${playlist.id}" title="Play">
|
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/>
|
||||||
${SVG_PLAY}
|
<line x1="10" y1="11" x2="10" y2="17"/>
|
||||||
</button>
|
<line x1="14" y1="11" x2="14" y2="17"/>
|
||||||
</div>
|
</svg>
|
||||||
<div class="card-info">
|
</button>
|
||||||
<h4 class="card-title">${playlist.name}</h4>
|
`,
|
||||||
<p class="card-subtitle">${playlist.tracks ? playlist.tracks.length : (playlist.numberOfTracks || 0)} tracks</p>
|
isCompact,
|
||||||
</div>
|
extraClasses: 'user-playlist'
|
||||||
</div>
|
});
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createAlbumCardHTML(album) {
|
createAlbumCardHTML(album) {
|
||||||
|
|
@ -324,53 +347,49 @@ export class UIRenderer {
|
||||||
let yearDisplay = '';
|
let yearDisplay = '';
|
||||||
if (album.releaseDate) {
|
if (album.releaseDate) {
|
||||||
const date = new Date(album.releaseDate);
|
const date = new Date(album.releaseDate);
|
||||||
if (!isNaN(date.getTime())) {
|
if (!isNaN(date.getTime())) yearDisplay = `${date.getFullYear()}`;
|
||||||
yearDisplay = `${date.getFullYear()}`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let typeLabel = '';
|
let typeLabel = '';
|
||||||
if (album.type === 'EP') {
|
if (album.type === 'EP') typeLabel = ' • EP';
|
||||||
typeLabel = ' • EP';
|
else if (album.type === 'SINGLE') typeLabel = ' • Single';
|
||||||
} else if (album.type === 'SINGLE') {
|
|
||||||
typeLabel = ' • Single';
|
|
||||||
}
|
|
||||||
|
|
||||||
const isCompact = cardSettings.isCompactAlbum();
|
const isCompact = cardSettings.isCompactAlbum();
|
||||||
|
|
||||||
return `
|
return this.createBaseCardHTML({
|
||||||
<div class="card ${isCompact ? 'compact' : ''}" data-album-id="${album.id}" data-href="#album/${album.id}" style="cursor: pointer;">
|
type: 'album',
|
||||||
<div class="card-image-wrapper">
|
id: album.id,
|
||||||
<img src="${this.api.getCoverUrl(album.cover)}" alt="${album.title}" class="card-image" loading="lazy">
|
href: `#album/${album.id}`,
|
||||||
<button class="like-btn card-like-btn" data-action="toggle-like" data-type="album" title="Add to Liked">
|
title: `${album.title} ${explicitBadge}`,
|
||||||
${this.createHeartIcon(false)}
|
subtitle: `${album.artist?.name ?? ''} • ${yearDisplay}${typeLabel}`,
|
||||||
</button>
|
imageHTML: `<img src="${this.api.getCoverUrl(album.cover)}" alt="${album.title}" class="card-image" loading="lazy">`,
|
||||||
<button class="play-btn card-play-btn" data-action="play-card" data-type="album" data-id="${album.id}" title="Play">
|
actionButtonsHTML: `
|
||||||
${SVG_PLAY}
|
<button class="like-btn card-like-btn" data-action="toggle-like" data-type="album" title="Add to Liked">
|
||||||
</button>
|
${this.createHeartIcon(false)}
|
||||||
</div>
|
</button>
|
||||||
<div class="card-info">
|
`,
|
||||||
<h4 class="card-title">${album.title} ${explicitBadge}</h4>
|
isCompact
|
||||||
<p class="card-subtitle">${album.artist?.name ?? ''}</p>
|
});
|
||||||
<p class="card-subtitle">${yearDisplay}${typeLabel}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createArtistCardHTML(artist) {
|
createArtistCardHTML(artist) {
|
||||||
const isCompact = cardSettings.isCompactArtist();
|
const isCompact = cardSettings.isCompactArtist();
|
||||||
return `
|
|
||||||
<div class="card artist ${isCompact ? 'compact' : ''}" data-artist-id="${artist.id}" data-href="#artist/${artist.id}" style="cursor: pointer;">
|
return this.createBaseCardHTML({
|
||||||
<div class="card-image-wrapper">
|
type: 'artist',
|
||||||
<img src="${this.api.getArtistPictureUrl(artist.picture)}" alt="${artist.name}" class="card-image" loading="lazy">
|
id: artist.id,
|
||||||
<button class="like-btn card-like-btn" data-action="toggle-like" data-type="artist" title="Add to Liked">
|
href: `#artist/${artist.id}`,
|
||||||
${this.createHeartIcon(false)}
|
title: artist.name,
|
||||||
</button>
|
subtitle: '',
|
||||||
</div>
|
imageHTML: `<img src="${this.api.getArtistPictureUrl(artist.picture)}" alt="${artist.name}" class="card-image" loading="lazy">`,
|
||||||
<h4 class="card-title">${artist.name}</h4>
|
actionButtonsHTML: `
|
||||||
</div>
|
<button class="like-btn card-like-btn" data-action="toggle-like" data-type="artist" title="Add to Liked">
|
||||||
`;
|
${this.createHeartIcon(false)}
|
||||||
|
</button>
|
||||||
|
`,
|
||||||
|
isCompact,
|
||||||
|
extraClasses: 'artist'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
createSkeletonTrack(showCover = false) {
|
createSkeletonTrack(showCover = false) {
|
||||||
|
|
|
||||||
123
styles.css
123
styles.css
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
color-scheme: light dark;
|
color-scheme: light dark;
|
||||||
--spacing-xs: 0.4rem;
|
--spacing-xs: 0.4rem;
|
||||||
|
|
@ -166,7 +165,7 @@
|
||||||
:root[data-theme="frappe"] {
|
:root[data-theme="frappe"] {
|
||||||
color-scheme: dark;
|
color-scheme: dark;
|
||||||
--background: #303446;
|
--background: #303446;
|
||||||
--foreground:#c6d0f5;
|
--foreground: #c6d0f5;
|
||||||
--card: #414559;
|
--card: #414559;
|
||||||
--card-foreground: #949cbb;
|
--card-foreground: #949cbb;
|
||||||
--primary: #8caaee;
|
--primary: #8caaee;
|
||||||
|
|
@ -334,8 +333,8 @@ kbd {
|
||||||
transition: opacity 0.5s ease-in-out;
|
transition: opacity 0.5s ease-in-out;
|
||||||
|
|
||||||
/* Fade out at the bottom */
|
/* Fade out at the bottom */
|
||||||
mask-image: linear-gradient(to bottom, rgba(0,0,0,1) 0%, rgba(0,0,0,0.8) 40%, rgba(0,0,0,0) 100%);
|
mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.8) 40%, rgba(0, 0, 0, 0) 100%);
|
||||||
-webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,1) 0%, rgba(0,0,0,0.8) 40%, rgba(0,0,0,0) 100%);
|
-webkit-mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.8) 40%, rgba(0, 0, 0, 0) 100%);
|
||||||
|
|
||||||
/* Blur effect */
|
/* Blur effect */
|
||||||
filter: var(--cover-filter);
|
filter: var(--cover-filter);
|
||||||
|
|
@ -348,8 +347,8 @@ kbd {
|
||||||
|
|
||||||
/* Light mode adjustments */
|
/* Light mode adjustments */
|
||||||
:root[data-theme="light"] #page-background {
|
:root[data-theme="light"] #page-background {
|
||||||
mask-image: linear-gradient(to bottom, rgba(0,0,0,1) 0%, rgba(0,0,0,0) 100%);
|
mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0) 100%);
|
||||||
-webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,1) 0%, rgba(0,0,0,0) 100%);
|
-webkit-mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0) 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.now-playing-bar {
|
.now-playing-bar {
|
||||||
|
|
@ -529,6 +528,7 @@ body.has-page-background .track-item:hover {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateY(4px);
|
transform: translateY(4px);
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
|
|
@ -540,6 +540,7 @@ body.has-page-background .track-item:hover {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: scale(0.95);
|
transform: scale(0.95);
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
|
|
@ -551,6 +552,7 @@ body.has-page-background .track-item:hover {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(100%);
|
transform: translateX(100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
|
|
@ -562,6 +564,7 @@ body.has-page-background .track-item:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(100%);
|
transform: translateX(100%);
|
||||||
|
|
@ -569,17 +572,31 @@ body.has-page-background .track-item:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
to { transform: rotate(360deg); }
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes pulse {
|
@keyframes pulse {
|
||||||
0%, 100% { opacity: 1; }
|
|
||||||
50% { opacity: 0.5; }
|
0%,
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes skeleton-loading {
|
@keyframes skeleton-loading {
|
||||||
0% { background-position: 200% 0; }
|
0% {
|
||||||
100% { background-position: -200% 0; }
|
background-position: 200% 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
background-position: -200% 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.animate-spin {
|
.animate-spin {
|
||||||
|
|
@ -1655,7 +1672,7 @@ input:checked + .slider::before {
|
||||||
max-width: 80vw;
|
max-width: 80vw;
|
||||||
max-height: 60vh;
|
max-height: 60vh;
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
box-shadow: 0 20px 50px rgba(0,0,0,0.5);
|
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|
@ -1842,6 +1859,11 @@ input:checked + .slider::before {
|
||||||
.queue-track-item .queue-remove-btn {
|
.queue-track-item .queue-remove-btn {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hide like button on compact cards on mobile */
|
||||||
|
.card.compact .card-like-btn {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.queue-track-item .queue-remove-btn:hover {
|
.queue-track-item .queue-remove-btn:hover {
|
||||||
|
|
@ -1864,12 +1886,10 @@ input:checked + .slider::before {
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeleton {
|
.skeleton {
|
||||||
background: linear-gradient(
|
background: linear-gradient(90deg,
|
||||||
90deg,
|
var(--secondary) 0%,
|
||||||
var(--secondary) 0%,
|
var(--muted) 50%,
|
||||||
var(--muted) 50%,
|
var(--secondary) 100%);
|
||||||
var(--secondary) 100%
|
|
||||||
);
|
|
||||||
background-size: 200% 100%;
|
background-size: 200% 100%;
|
||||||
animation: skeleton-loading 1.5s ease-in-out infinite;
|
animation: skeleton-loading 1.5s ease-in-out infinite;
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
|
|
@ -3007,6 +3027,7 @@ input:checked + .slider::before {
|
||||||
padding-top: max(var(--spacing-md), env(safe-area-inset-top));
|
padding-top: max(var(--spacing-md), env(safe-area-inset-top));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Side Panels (Lyrics & Queue) */
|
/* Side Panels (Lyrics & Queue) */
|
||||||
:root {
|
:root {
|
||||||
--player-bar-height-desktop: 90px;
|
--player-bar-height-desktop: 90px;
|
||||||
|
|
@ -3178,14 +3199,46 @@ input:checked + .slider::before {
|
||||||
color: var(--muted-foreground);
|
color: var(--muted-foreground);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compact Card Play Button */
|
||||||
|
.card.compact .card-play-btn {
|
||||||
|
right: 0.5rem;
|
||||||
|
top: 25%;
|
||||||
|
width: 36px !important;
|
||||||
|
height: 36px !important;
|
||||||
|
background-color: var(--primary) !important;
|
||||||
|
color: var(--primary-foreground) !important;
|
||||||
|
box-shadow: var(--shadow-md);
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide play button initially on desktop (hover capable), show on hover */
|
||||||
|
@media (hover: hover) {
|
||||||
|
.card.compact .card-play-btn {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card.compact:hover .card-play-btn {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjust like button for compact size */
|
||||||
.card.compact .card-like-btn {
|
.card.compact .card-like-btn {
|
||||||
display: none !important;
|
width: 24px !important;
|
||||||
|
height: 24px !important;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card.compact:hover .card-like-btn {
|
.card.compact:hover .card-like-btn {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card.compact.user-playlist .edit-playlist-btn,
|
||||||
|
.card.compact.user-playlist .delete-playlist-btn {
|
||||||
|
display: none !important; /* Hide edit/delete on compact view to prevent covering image */
|
||||||
|
}
|
||||||
|
|
||||||
/* Mobile adjustments */
|
/* Mobile adjustments */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.side-panel {
|
.side-panel {
|
||||||
|
|
@ -3270,6 +3323,7 @@ input:checked + .slider::before {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: color var(--transition);
|
transition: color var(--transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
.now-playing-bar .artist .artist-link:hover {
|
.now-playing-bar .artist .artist-link:hover {
|
||||||
color: var(--highlight);
|
color: var(--highlight);
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
|
|
@ -3384,10 +3438,10 @@ img:not([src]), img[src=''] {
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-bar {
|
.search-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 80%;
|
width: 80%;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -3445,24 +3499,21 @@ img:not([src]), img[src=''] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#playlist-modal {
|
#playlist-modal {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
animation-name: fadeInOpacity;
|
animation-name: fadeInOpacity;
|
||||||
animation-iteration-count: 1;
|
animation-iteration-count: 1;
|
||||||
animation-timing-function: ease-in;
|
animation-timing-function: ease-in;
|
||||||
animation-duration: 0.1s;
|
animation-duration: 0.1s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fadeInOpacity {
|
@keyframes fadeInOpacity {
|
||||||
0% {
|
0% {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
100% {
|
100% {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fuck this chud ass shit bro */
|
/* fuck this chud ass shit bro */
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue