Add album view for playlists (#1700)

* update client side song ordering to include album order

* add compact styling to LibraryHeader

* move search button to top right of LibraryHeader
This commit is contained in:
Jeff
2026-02-11 21:48:25 -08:00
committed by GitHub
parent 9cde569c7d
commit e6f49b9f1f
20 changed files with 918 additions and 103 deletions
@@ -1,3 +1,10 @@
.top-right {
position: absolute;
top: var(--theme-spacing-lg);
right: var(--theme-spacing-md);
z-index: 20;
}
.library-header {
position: relative;
display: grid;
@@ -56,6 +63,52 @@
height: 250px;
}
}
&.compact {
min-height: unset;
padding: var(--theme-spacing-md) var(--theme-spacing-xs);
:global(.item-image-placeholder) {
width: 250px !important;
height: 250px;
}
.image {
width: 250px !important;
height: 250px;
}
@container (min-width: $mantine-breakpoint-sm) {
grid-template-columns: 200px minmax(0, 1fr);
min-height: unset;
padding: var(--theme-spacing-md) var(--theme-spacing-sm);
.image {
width: 200px !important;
height: 200px;
}
:global(.item-image-placeholder) {
width: 200px !important;
height: 200px;
}
}
@container (min-width: $mantine-breakpoint-lg) {
grid-template-columns: 200px minmax(0, 1fr);
padding: var(--theme-spacing-md) var(--theme-spacing-md);
.image {
width: 200px !important;
height: 200px;
}
:global(.item-image-placeholder) {
width: 200px !important;
height: 200px;
}
}
}
}
.image-section {
@@ -32,6 +32,7 @@ import { Play } from '/@/shared/types/types';
interface LibraryHeaderProps {
children?: ReactNode;
compact?: boolean;
containerClassName?: string;
imagePlaceholderUrl?: null | string;
imageUrl?: null | string;
@@ -45,11 +46,20 @@ interface LibraryHeaderProps {
};
loading?: boolean;
title: string;
topRight?: ReactNode;
}
export const LibraryHeader = forwardRef(
(
{ children, containerClassName, imageUrl, item, title }: LibraryHeaderProps,
{
children,
compact,
containerClassName,
imageUrl,
item,
title,
topRight,
}: LibraryHeaderProps,
ref: Ref<HTMLDivElement>,
) => {
const { t } = useTranslation();
@@ -125,7 +135,15 @@ export const LibraryHeader = forwardRef(
}, [item.explicitStatus, item.imageId, item.type]);
return (
<div className={clsx(styles.libraryHeader, containerClassName)} ref={ref}>
<div
className={clsx(
styles.libraryHeader,
containerClassName,
compact && styles.compact,
)}
ref={ref}
>
{topRight && <div className={styles.topRight}>{topRight}</div>}
<div
className={styles.imageSection}
onClick={() => {
@@ -224,6 +224,11 @@ export const CLIENT_SIDE_ALBUM_FILTERS = [
name: i18n.t('filter.albumArtist', { postProcess: 'titleCase' }),
value: AlbumListSort.ALBUM_ARTIST,
},
{
defaultOrder: SortOrder.ASC,
name: i18n.t('filter.id', { postProcess: 'titleCase' }),
value: AlbumListSort.ID,
},
{
defaultOrder: SortOrder.DESC,
name: i18n.t('filter.duration', { postProcess: 'titleCase' }),
@@ -295,6 +300,11 @@ const ALBUM_LIST_FILTERS: Partial<
name: i18n.t('filter.albumArtist', { postProcess: 'titleCase' }),
value: AlbumListSort.ALBUM_ARTIST,
},
{
defaultOrder: SortOrder.ASC,
name: i18n.t('filter.id', { postProcess: 'titleCase' }),
value: AlbumListSort.ID,
},
{
defaultOrder: SortOrder.DESC,
name: i18n.t('filter.communityRating', { postProcess: 'titleCase' }),
@@ -337,6 +347,11 @@ const ALBUM_LIST_FILTERS: Partial<
name: i18n.t('filter.albumArtist', { postProcess: 'titleCase' }),
value: AlbumListSort.ALBUM_ARTIST,
},
{
defaultOrder: SortOrder.ASC,
name: i18n.t('filter.id', { postProcess: 'titleCase' }),
value: AlbumListSort.ID,
},
{
defaultOrder: SortOrder.ASC,
name: i18n.t('filter.artist', { postProcess: 'titleCase' }),
@@ -399,6 +414,11 @@ const ALBUM_LIST_FILTERS: Partial<
name: i18n.t('filter.albumArtist', { postProcess: 'titleCase' }),
value: AlbumListSort.ALBUM_ARTIST,
},
{
defaultOrder: SortOrder.ASC,
name: i18n.t('filter.id', { postProcess: 'titleCase' }),
value: AlbumListSort.ID,
},
{
defaultOrder: SortOrder.DESC,
name: i18n.t('filter.mostPlayed', { postProcess: 'titleCase' }),