add close button to expanded list item

This commit is contained in:
jeffvli
2025-11-13 13:03:15 -08:00
parent af480e8283
commit a24b870faa
3 changed files with 62 additions and 16 deletions
@@ -3,8 +3,8 @@ import { Suspense } from 'react';
import styles from './expanded-list-item.module.css'; import styles from './expanded-list-item.module.css';
import { import {
ItemListStateItem,
ItemListStateActions, ItemListStateActions,
ItemListStateItem,
} from '/@/renderer/components/item-list/helpers/item-list-state'; } from '/@/renderer/components/item-list/helpers/item-list-state';
import { ExpandedAlbumListItem } from '/@/renderer/features/albums/components/expanded-album-list-item'; import { ExpandedAlbumListItem } from '/@/renderer/features/albums/components/expanded-album-list-item';
import { Spinner } from '/@/shared/components/spinner/spinner'; import { Spinner } from '/@/shared/components/spinner/spinner';
@@ -27,7 +27,11 @@ export const ExpandedListItem = ({ internalState, itemType }: ExpandedListItemPr
<div className={styles.container}> <div className={styles.container}>
<div className={styles.inner}> <div className={styles.inner}>
<Suspense fallback={<Spinner container />}> <Suspense fallback={<Spinner container />}>
<SelectedItem item={currentItem} itemType={itemType} /> <SelectedItem
internalState={internalState}
item={currentItem as ItemListStateItem}
itemType={itemType}
/>
</Suspense> </Suspense>
</div> </div>
</div> </div>
@@ -35,14 +39,15 @@ export const ExpandedListItem = ({ internalState, itemType }: ExpandedListItemPr
}; };
interface SelectedItemProps { interface SelectedItemProps {
internalState: ItemListStateActions;
item: ItemListStateItem; item: ItemListStateItem;
itemType: LibraryItem; itemType: LibraryItem;
} }
const SelectedItem = ({ item, itemType }: SelectedItemProps) => { const SelectedItem = ({ internalState, item, itemType }: SelectedItemProps) => {
switch (itemType) { switch (itemType) {
case LibraryItem.ALBUM: case LibraryItem.ALBUM:
return <ExpandedAlbumListItem item={item} />; return <ExpandedAlbumListItem internalState={internalState} item={item} />;
default: default:
return null; return null;
} }
@@ -31,6 +31,20 @@
gap: var(--theme-spacing-xs); gap: var(--theme-spacing-xs);
} }
.header-title {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
}
.close-button {
position: absolute;
top: 0;
right: 0;
z-index: 10;
}
.content { .content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -45,6 +59,7 @@
.item-title { .item-title {
z-index: 10; z-index: 10;
display: -webkit-box; display: -webkit-box;
padding-right: var(--theme-spacing-xl);
overflow: hidden; overflow: hidden;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
line-clamp: 2; line-clamp: 2;
@@ -116,15 +131,15 @@
min-height: 0; min-height: 0;
@container (min-width: 640px) { @container (min-width: 640px) {
width: 50%; width: 60%;
} }
@container (min-width: 768px) { @container (min-width: 768px) {
width: 40%; width: 50%;
} }
@container (min-width: 1200px) { @container (min-width: 1200px) {
width: 30%; width: 40%;
} }
} }
@@ -136,7 +151,7 @@
.track-row { .track-row {
position: relative; position: relative;
display: grid; display: grid;
grid-template-columns: 55px 1fr 50px; grid-template-columns: 55px 1fr 55px;
gap: var(--theme-spacing-sm); gap: var(--theme-spacing-sm);
align-items: center; align-items: center;
padding: var(--theme-spacing-xs) var(--theme-spacing-sm); padding: var(--theme-spacing-xs) var(--theme-spacing-sm);
@@ -18,6 +18,7 @@ import { ItemListItem } from '/@/renderer/components/item-list/types';
import { albumQueries } from '/@/renderer/features/albums/api/album-api'; import { albumQueries } from '/@/renderer/features/albums/api/album-api';
import { useFastAverageColor } from '/@/renderer/hooks'; import { useFastAverageColor } from '/@/renderer/hooks';
import { useDragDrop } from '/@/renderer/hooks/use-drag-drop'; import { useDragDrop } from '/@/renderer/hooks/use-drag-drop';
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
import { Group } from '/@/shared/components/group/group'; import { Group } from '/@/shared/components/group/group';
import { ScrollArea } from '/@/shared/components/scroll-area/scroll-area'; import { ScrollArea } from '/@/shared/components/scroll-area/scroll-area';
import { Separator } from '/@/shared/components/separator/separator'; import { Separator } from '/@/shared/components/separator/separator';
@@ -40,6 +41,7 @@ interface AlbumTracksTableProps {
} }
interface ExpandedAlbumListItemProps { interface ExpandedAlbumListItemProps {
internalState?: ItemListStateActions;
item: ItemListStateItem; item: ItemListStateItem;
} }
@@ -163,7 +165,7 @@ const AlbumTracksTable = ({ isDark, serverId, songs }: AlbumTracksTableProps) =>
); );
}; };
export const ExpandedAlbumListItem = ({ item }: ExpandedAlbumListItemProps) => { export const ExpandedAlbumListItem = ({ internalState, item }: ExpandedAlbumListItemProps) => {
const { data, isLoading } = useSuspenseQuery( const { data, isLoading } = useSuspenseQuery(
albumQueries.detail({ albumQueries.detail({
query: { id: item.id }, query: { id: item.id },
@@ -201,13 +203,37 @@ export const ExpandedAlbumListItem = ({ item }: ExpandedAlbumListItemProps) => {
<div className={styles.expanded}> <div className={styles.expanded}>
<div className={styles.content}> <div className={styles.content}>
<div className={styles.header}> <div className={styles.header}>
<TextTitle <div className={styles.headerTitle}>
className={clsx(styles.itemTitle, { [styles.dark]: color.isDark })} <TextTitle
fw={700} className={clsx(styles.itemTitle, {
order={4} [styles.dark]: color.isDark,
> })}
{data?.name} fw={700}
</TextTitle> order={4}
>
{data?.name}
</TextTitle>
{internalState && (
<ActionIcon
className={clsx(styles.closeButton, {
[styles.dark]: color.isDark,
})}
icon="x"
iconProps={{
size: 'xl',
}}
onClick={() => {
const rowId = internalState.extractRowId(item);
if (rowId) {
internalState.clearExpanded();
}
}}
radius="50%"
size="sm"
variant="subtle"
/>
)}
</div>
<Group <Group
className={clsx(styles.itemSubtitle, { className={clsx(styles.itemSubtitle, {
[styles.dark]: color.isDark, [styles.dark]: color.isDark,