Files
yellowjacket/frontend/src/components/cover-grid/cover-grid-styles.ts
T
logan 792e87298b
CI / check (push) Skipped
CI / e2e (push) Skipped
CI / check (pull_request) Successful in 2m30s
CI / e2e (pull_request) Successful in 6m5s
fix(ui): stop the album grid eating the year it was sorted by
The year sat inside the same ellipsis box as the title, so it was the
first thing truncation took: a card wide enough for a long album name
never showed its year, and browsing the grid *by year* showed years
only for the albums with short names. The sort said one thing and the
cards showed another.

Title and year are now a flex row where only the title gives way. A
row rather than a second line, because the card's height is what the
virtualizer measures rows by.

Refs #29
2026-08-18 11:08:37 -04:00

190 lines
5.2 KiB
TypeScript

import { css } from 'lit';
import { contextMenuStyles } from '@utils/context-menu-controller.js';
import { designTokens } from '../../styles/tokens.css';
/** Component-specific styles for the cover grid. */
const gridStyles = css`
:host {
display: flex;
flex-direction: column;
overflow: hidden;
height: 100%;
position: relative;
contain: layout style;
}
/*
* The scroller. artists-view and genres-view carry the same
* markup with this rule; cover-grid had the class and no rule for
* it, so nothing in the albums view scrolled — the container grew to
* its full content height inside an overflow: hidden host and
* everything past the first screenful was unreachable by wheel,
* keyboard or scrollbar. Invisible on the eight-album fixture and
* fatal on a real library: measured at 5 000 albums, 186 984 px of
* content in a 772 px box.
*
* It is also what the dropdown's scroll manager was written
* against — it saves and restores this element's scrollTop, which
* was permanently 0.
*/
.grid-scroll-container {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
contain: paint;
}
/* ========================================
* Album card
* ======================================== */
.album-card {
display: flex;
flex-direction: column;
cursor: pointer;
padding: 5px;
/* border-radius removed — forces anti-aliased path clipping on
every paint of every visible card; cover image retains its own
4px radius via .cover-container */
box-sizing: border-box;
width: var(--card-width, 176px);
}
.album-card:hover {
background-color: var(--yj-hover-overlay, rgba(255, 255, 255, 0.1));
}
.album-card.selected {
outline: 2px solid var(--yj-accent, #ffd43b);
outline-offset: 2px;
}
.album-card:focus-visible {
outline: 2px solid var(--yj-accent, #ffd43b);
outline-offset: 2px;
}
.cover-container {
position: relative;
width: 100%;
aspect-ratio: 1;
border-radius: 4px;
overflow: hidden;
background-color: var(--yj-bg-surface, #282828);
/* transition removed — software rendering repaints per frame */
}
.album-card.selected .cover-container {
scale: 0.95;
}
.cover-image {
width: 100%;
height: 100%;
object-fit: cover;
-webkit-user-drag: none;
}
.placeholder-cover {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(
135deg,
var(--yj-bg-overlay, #404040) 0%,
var(--yj-bg-surface, #282828) 100%
);
color: var(--yj-text-secondary, #b3b3b3);
font-size: var(--placeholder-font, 48px);
}
.album-info {
margin-top: 4px;
min-width: 0;
text-align: center;
/* transition removed — software rendering repaints per frame */
}
.album-card.selected .album-info {
scale: 0.95;
}
/* Title and year on one line, and only the title truncates.
The year used to be part of the same run of text, so it was the
first thing an ellipsis ate: a card wide enough for a long album
name never showed its year, and browsing by year showed years
only for the albums with short names -- the sort said one thing
and the cards showed another.
A flex row rather than a second line, because the card's height
is what the virtualizer measures rows by. */
.album-name {
font-size: var(--album-name-font, 14px);
font-weight: 400;
color: var(--yj-text-primary, #fff);
display: flex;
justify-content: center;
align-items: baseline;
gap: 0.35em;
min-width: 0;
}
.album-title {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
}
.artist-name {
font-size: var(--artist-name-font, 12px);
color: var(--yj-text-secondary, #b3b3b3);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-top: 2px;
}
.album-year {
color: var(--yj-text-tertiary, #888);
flex: 0 0 auto;
white-space: nowrap;
}
/* ========================================
* Shared states
* ======================================== */
.loading {
display: flex;
justify-content: center;
align-items: center;
padding: 32px;
color: var(--yj-text-secondary, #b3b3b3);
}
.empty-state {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 48px;
color: var(--yj-text-secondary, #b3b3b3);
text-align: center;
}
.empty-state p {
margin: 8px 0;
}
`;
/** Combined styles for the cover grid component. */
export const coverGridStyles = [
designTokens,
gridStyles,
contextMenuStyles,
];