v4: a playlist's cover is a banner over its header, and the edit form picks it in the same shape — the cover was a 72px square beside the title, which left the title and description a narrow column under a mostly empty band: on a phone, in Kanagawa's wide mono, a long title broke into six lines. The cover now spans the header's width above the title, cropped to 3:1 and no taller than 14rem, inside the header's padding so outlined themes keep their ring around it; the title, buttons, description and meta take the whole width under it. The edit form's Cover picker takes the same shape (.playlist-cover-banner, shared with .playlist-detail-img), and with no cover is a dashed 3:1 placeholder. ImagePicker's size is now optional, so a class can size it, and its radius takes any CSS length, here --radius-lg; a picker sized by aspect-ratio sets min-height: 0, or its image would hold it at its own height. 669 frontend tests pass, and tsc, eslint, deno fmt and doc:lint are clean; checked in screenshots in Kanagawa dark (French, 385px), Brutalist at 390px with and without a cover, and Smooth at 1100px, the page and the form.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
24
src/App.css
24
src/App.css
@@ -5344,17 +5344,31 @@ body.has-player .chat-fab {
|
||||
|
||||
.playlist-detail-header-top {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
/* The cover is a banner over the title, cropped to 3:1 and no taller than
|
||||
14rem on wide screens, and the edit form's picker takes the same shape. It
|
||||
stays inside the header's padding, so themes that outline panels with
|
||||
--panel-ring keep their ring around it. */
|
||||
.playlist-detail-img,
|
||||
.playlist-cover-banner {
|
||||
display: block;
|
||||
width: 100%;
|
||||
aspect-ratio: 3 / 1;
|
||||
max-height: 14rem;
|
||||
}
|
||||
|
||||
.playlist-detail-img {
|
||||
flex-shrink: 0;
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
object-fit: cover;
|
||||
border-radius: var(--radius-lg);
|
||||
border: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
/* Or the picker's image would hold it at its own height: a box sized by
|
||||
aspect-ratio grows to fit its content. */
|
||||
.playlist-cover-banner {
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.playlist-detail-title-row {
|
||||
|
||||
@@ -144,7 +144,8 @@ export function PlaylistEditForm(
|
||||
? playlistImageUrl(playlist, mediaToken)
|
||||
: null)}
|
||||
alt="Cover"
|
||||
size={72}
|
||||
className="playlist-cover-banner"
|
||||
borderRadius="var(--radius-lg)"
|
||||
onChange={(file) => {
|
||||
field.onChange(file);
|
||||
setImagePreview(URL.createObjectURL(file));
|
||||
|
||||
@@ -16,9 +16,10 @@ export interface ImagePickerProps {
|
||||
/** Shows a "+" placeholder when null. */
|
||||
src: string | null;
|
||||
alt?: string;
|
||||
/** Sets the side, in pixels. */
|
||||
/** Sets the side, in pixels. Without it, `className` sizes the picker. */
|
||||
size?: number;
|
||||
borderRadius?: number;
|
||||
/** In pixels when a number, or any CSS length, such as a radius token. */
|
||||
borderRadius?: number | string;
|
||||
/** Called with the file picked. The same file can be picked again. */
|
||||
onChange: (file: File) => void;
|
||||
/** Disables the picker and shows "…" while the caller uploads. */
|
||||
@@ -35,7 +36,7 @@ export interface ImagePickerProps {
|
||||
export function ImagePicker({
|
||||
src,
|
||||
alt = "",
|
||||
size = 80,
|
||||
size,
|
||||
borderRadius = 8,
|
||||
onChange,
|
||||
uploading = false,
|
||||
@@ -43,7 +44,9 @@ export function ImagePicker({
|
||||
className,
|
||||
}: ImagePickerProps): React.JSX.Element {
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const sizeStyle = { width: size, height: size, borderRadius };
|
||||
const sizeStyle = size === undefined
|
||||
? { borderRadius }
|
||||
: { width: size, height: size, borderRadius };
|
||||
const pick = () => {
|
||||
if (!uploading) inputRef.current?.click();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user