diff --git a/src/renderer/components/item-list/expanded-list-item.module.css b/src/renderer/components/item-list/expanded-list-item.module.css
index bfe342bbf..5d139ef3d 100644
--- a/src/renderer/components/item-list/expanded-list-item.module.css
+++ b/src/renderer/components/item-list/expanded-list-item.module.css
@@ -1,7 +1,7 @@
.container {
width: 100%;
height: 100%;
- padding: var(--theme-spacing-lg);
+ padding: var(--theme-spacing-sm);
}
.inner {
diff --git a/src/renderer/components/item-list/expanded-list-item.tsx b/src/renderer/components/item-list/expanded-list-item.tsx
index d03b01815..cbf8992a7 100644
--- a/src/renderer/components/item-list/expanded-list-item.tsx
+++ b/src/renderer/components/item-list/expanded-list-item.tsx
@@ -1,3 +1,5 @@
+import { Suspense } from 'react';
+
import styles from './expanded-list-item.module.css';
import {
@@ -5,6 +7,7 @@ import {
ItemListStateActions,
} from '/@/renderer/components/item-list/helpers/item-list-state';
import { ExpandedAlbumListItem } from '/@/renderer/features/albums/components/expanded-album-list-item';
+import { Spinner } from '/@/shared/components/spinner/spinner';
import { LibraryItem } from '/@/shared/types/domain-types';
interface ExpandedListItemProps {
@@ -23,7 +26,9 @@ export const ExpandedListItem = ({ internalState, itemType }: ExpandedListItemPr
return (
);
diff --git a/src/renderer/features/albums/components/expanded-album-list-item.module.css b/src/renderer/features/albums/components/expanded-album-list-item.module.css
index 2e0a1ff17..c94abeed5 100644
--- a/src/renderer/features/albums/components/expanded-album-list-item.module.css
+++ b/src/renderer/features/albums/components/expanded-album-list-item.module.css
@@ -2,6 +2,8 @@
position: relative;
width: 100%;
height: 100%;
+ container-name: expanded-album-list-item;
+ container-type: inline-size;
background-color: var(--theme-colors-surface);
border-radius: var(--theme-radius-md);
}
@@ -12,3 +14,129 @@
bottom: 0;
padding: var(--theme-spacing-sm);
}
+
+.expanded {
+ position: relative;
+ gap: var(--theme-spacing-md);
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ user-select: none;
+ border-radius: var(--theme-radius-md);
+}
+
+.header {
+ display: flex;
+ flex-direction: column;
+ gap: var(--theme-spacing-xs);
+}
+
+.content {
+ display: flex;
+ flex-direction: column;
+ gap: var(--theme-spacing-md);
+ width: 100%;
+ height: 100%;
+ min-height: 0;
+ padding: var(--theme-spacing-md);
+ overflow: hidden;
+}
+
+.item-title {
+ z-index: 100;
+ display: -webkit-box;
+ overflow: hidden;
+ -webkit-line-clamp: 2;
+ line-clamp: 2;
+ line-height: 1.3;
+ color: black;
+ -webkit-box-orient: vertical;
+}
+
+.item-subtitle {
+ color: black;
+ white-space: nowrap;
+}
+
+.dark {
+ color: white;
+}
+
+.image-container {
+ position: absolute;
+ top: 0;
+ right: 0;
+ z-index: 1;
+ display: flex;
+ grid-area: image;
+ align-items: center;
+ justify-content: center;
+ width: 50%;
+ height: 100%;
+}
+
+.background-image {
+ position: absolute;
+ right: 0;
+ width: 60%;
+ height: 100%;
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: cover;
+ filter: blur(2px);
+
+ &::before {
+ position: absolute;
+ inset: 0;
+ content: '';
+ background: linear-gradient(to right, var(--bg-color) 0%, transparent 100%);
+ }
+
+ @container (min-width: 640px) {
+ width: 80%;
+ }
+
+ @container (min-width: 768px) {
+ width: 90%;
+ }
+
+ @container (min-width: 1200px) {
+ width: 100%;
+ }
+}
+
+.tracks {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ gap: var(--theme-spacing-sm);
+ width: 60%;
+ max-width: 700px;
+ min-height: 0;
+
+ @container (min-width: 640px) {
+ width: 50%;
+ }
+
+ @container (min-width: 768px) {
+ width: 40%;
+ }
+
+ @container (min-width: 1200px) {
+ width: 30%;
+ }
+}
+
+.tracks * {
+ color: black;
+
+ /* stylelint-disable-next-line selector-class-pattern */
+ :global(.table-row-module_row) {
+ /* height: var(--table-row-config-condensed-height); */
+ border-bottom: none;
+ }
+}
+
+.tracks.dark * {
+ color: white;
+}
diff --git a/src/renderer/features/albums/components/expanded-album-list-item.tsx b/src/renderer/features/albums/components/expanded-album-list-item.tsx
index 9a694dee9..5d8a5070c 100644
--- a/src/renderer/features/albums/components/expanded-album-list-item.tsx
+++ b/src/renderer/features/albums/components/expanded-album-list-item.tsx
@@ -1,77 +1,122 @@
-import { useQuery } from '@tanstack/react-query';
+import { useSuspenseQuery } from '@tanstack/react-query';
+import clsx from 'clsx';
+import formatDuration from 'format-duration';
import { motion } from 'motion/react';
-import { useEffect, useRef, useTransition } from 'react';
+import { Fragment, Suspense } from 'react';
import styles from './expanded-album-list-item.module.css';
import { ItemListItem } from '/@/renderer/components/item-list/helpers/item-list-state';
import { albumQueries } from '/@/renderer/features/albums/api/album-api';
import { useFastAverageColor } from '/@/renderer/hooks';
+import { Group } from '/@/shared/components/group/group';
+import { ScrollArea } from '/@/shared/components/scroll-area/scroll-area';
+import { Separator } from '/@/shared/components/separator/separator';
import { Spinner } from '/@/shared/components/spinner/spinner';
+import { Table } from '/@/shared/components/table/table';
+import { TextTitle } from '/@/shared/components/text-title/text-title';
+import { Text } from '/@/shared/components/text/text';
interface ExpandedAlbumListItemProps {
item: ItemListItem;
- previousItem?: ItemListItem | null;
}
-export const ExpandedAlbumListItem = ({ item, previousItem }: ExpandedAlbumListItemProps) => {
- const [, startTransition] = useTransition();
- const previousDataRef = useRef(null);
-
- const { data, isLoading } = useQuery(
+export const ExpandedAlbumListItem = ({ item }: ExpandedAlbumListItemProps) => {
+ const { data, isLoading } = useSuspenseQuery(
albumQueries.detail({
- options: {},
query: { id: item.id },
serverId: item.serverId,
}),
);
- // Store the previous data when we have new data
- useEffect(() => {
- if (data && !isLoading) {
- previousDataRef.current = data;
- }
- }, [data, isLoading]);
-
- // Use current data if available, otherwise use previous data for smooth transition
- const displayData = data || previousDataRef.current;
- const isDataTransitioning = isLoading && previousDataRef.current;
-
const color = useFastAverageColor({
+ algorithm: 'sqrt',
id: item.id,
- src: displayData?.imageUrl,
- srcLoaded: !isDataTransitioning,
+ src: data?.imageUrl,
+ srcLoaded: true,
});
- // Start transition when item changes
- useEffect(() => {
- if (previousItem && previousItem.id !== item.id) {
- startTransition(() => {});
- }
- }, [item.id, previousItem, startTransition]);
+ if (color.isLoading) {
+ return null;
+ }
return (
- {isDataTransitioning && (
+ {isLoading && (
)}
-
- ExpandedAlbumListItem - {displayData?.name || 'Loading...'}
-
+
+
+
+
+
+ {data?.name}
+
+
+ {data?.albumArtists.map((artist, index) => (
+
+
+ {artist.name}
+
+ {index < data?.albumArtists.length - 1 && }
+
+ ))}
+
+
+
+
+
+
+ {data?.songs?.map((song) => (
+
+
+ {song.discNumber} - {song.trackNumber}
+
+ {song.name}
+
+ {formatDuration(song.duration)}
+
+
+ ))}
+
+
+
+
+
+
+
+
);
};