Browse Source

Improvements to album page

- Link to album list
- Album artist specified
- Genres separated from artists
- Mouse wheel horizontal scroll
- Add link wrapper to enforce link max width
master
jeffvli 3 years ago
committed by Jeff
parent
commit
d5e59f9975
  1. 4
      src/components/layout/styled.tsx
  2. 184
      src/components/library/AlbumView.tsx
  3. 16
      src/components/shared/styled.ts

4
src/components/layout/styled.tsx

@ -242,10 +242,10 @@ export const PageHeaderSubtitleWrapper = styled.span`
font-size: 14px; font-size: 14px;
`; `;
export const PageHeaderSubtitleDataLine = styled.div<{ $top?: boolean }>` export const PageHeaderSubtitleDataLine = styled.div<{ $top?: boolean; $overflow?: boolean }>`
margin-top: ${(props) => (props.$top ? '0px' : '7px')}; margin-top: ${(props) => (props.$top ? '0px' : '7px')};
white-space: nowrap; white-space: nowrap;
overflow: auto; overflow: ${(props) => (props.$overflow ? 'visible' : 'auto')};
::-webkit-scrollbar { ::-webkit-scrollbar {
height: 4px; height: 4px;

184
src/components/library/AlbumView.tsx

@ -1,4 +1,4 @@
import React from 'react'; import React, { useRef } from 'react';
import _ from 'lodash'; import _ from 'lodash';
import { nanoid } from 'nanoid/non-secure'; import { nanoid } from 'nanoid/non-secure';
import { clipboard, shell } from 'electron'; import { clipboard, shell } from 'electron';
@ -45,7 +45,13 @@ import {
getPlayedSongsNotification, getPlayedSongsNotification,
isCached, isCached,
} from '../../shared/utils'; } from '../../shared/utils';
import { StyledButton, StyledPopover, StyledTagLink } from '../shared/styled'; import {
LinkWrapper,
StyledButton,
StyledLink,
StyledPopover,
StyledTagLink,
} from '../shared/styled';
import { setActive } from '../../redux/albumSlice'; import { setActive } from '../../redux/albumSlice';
import { import {
BlurredBackground, BlurredBackground,
@ -67,6 +73,8 @@ const AlbumView = ({ ...rest }: any) => {
const config = useAppSelector((state) => state.config); const config = useAppSelector((state) => state.config);
const history = useHistory(); const history = useHistory();
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const artistLineRef = useRef<any>();
const genreLineRef = useRef<any>();
const { id } = useParams<AlbumParams>(); const { id } = useParams<AlbumParams>();
const albumId = rest.id ? rest.id : id; const albumId = rest.id ? rest.id : id;
@ -319,8 +327,21 @@ const AlbumView = ({ ...rest }: any) => {
showTitleTooltip showTitleTooltip
subtitle={ subtitle={
<div> <div>
<PageHeaderSubtitleDataLine $top> <PageHeaderSubtitleDataLine $top $overflow>
<strong>ALBUM</strong> {data.songCount} songs {formatDuration(data.duration)} <StyledLink onClick={() => history.push('/library/album')}>ALBUM</StyledLink>{' '}
{data.albumArtist && (
<>
by{' '}
<LinkWrapper maxWidth="20vw">
<StyledLink
onClick={() => history.push(`/library/artist/${data.albumArtistId}`)}
>
<strong>{data.albumArtist}</strong>
</StyledLink>
</LinkWrapper>
</>
)}{' '}
{data.songCount} songs, {formatDuration(data.duration)}
{data.year && ( {data.year && (
<> <>
{' • '} {' • '}
@ -328,31 +349,79 @@ const AlbumView = ({ ...rest }: any) => {
</> </>
)} )}
</PageHeaderSubtitleDataLine> </PageHeaderSubtitleDataLine>
<PageHeaderSubtitleDataLine> <PageHeaderSubtitleDataLine
ref={genreLineRef}
onWheel={(e: any) => {
if (!e.shiftKey) {
if (e.deltaY === 0) return;
const position = genreLineRef.current.scrollLeft;
genreLineRef.current.scrollTo({
top: 0,
left: position + e.deltaY,
behavior: 'smooth',
});
}
}}
>
Added {formatDate(data.created)} Added {formatDate(data.created)}
</PageHeaderSubtitleDataLine> {data.genre.map((d: Genre, i: number) => {
<PageHeaderSubtitleDataLine>
{data.artist.map((d: Artist) => {
return ( return (
<StyledTagLink <>
key={nanoid()} {i === 0 && ' • '}
tabIndex={0} {i > 0 && ', '}
tooltip={d.title} <LinkWrapper maxWidth="13vw">
onClick={() => { <StyledLink
if (!rest.isModal) { key={nanoid()}
history.push(`/library/artist/${d.id}`); tabIndex={0}
} else { onClick={() => {
dispatch( if (!rest.isModal) {
addModalPage({ dispatch(setActive({ ...album.active, filter: d.title }));
pageType: 'artist', setTimeout(() => {
id: d.id, history.push(`/library/album?sortType=${d.title}`);
}) }, 50);
); }
} }}
}} onKeyDown={(e: any) => {
onKeyDown={(e: any) => { if (e.key === ' ' || e.key === 'Enter') {
if (e.key === ' ' || e.key === 'Enter') { e.preventDefault();
e.preventDefault(); if (!rest.isModal) {
dispatch(setActive({ ...album.active, filter: d.title }));
setTimeout(() => {
history.push(`/library/album?sortType=${d.title}`);
}, 50);
}
}
}}
>
{d.title}
</StyledLink>
</LinkWrapper>
</>
);
})}
</PageHeaderSubtitleDataLine>
<PageHeaderSubtitleDataLine
ref={artistLineRef}
onWheel={(e: any) => {
if (!e.shiftKey) {
if (e.deltaY === 0) return;
const position = artistLineRef.current.scrollLeft;
artistLineRef.current.scrollTo({
top: 0,
left: position + e.deltaY,
behavior: 'smooth',
});
}
}}
>
{data.artist ? (
data.artist.map((d: Artist) => {
return (
<StyledTagLink
key={nanoid()}
tabIndex={0}
tooltip={d.title}
onClick={() => {
if (!rest.isModal) { if (!rest.isModal) {
history.push(`/library/artist/${d.id}`); history.push(`/library/artist/${d.id}`);
} else { } else {
@ -363,43 +432,30 @@ const AlbumView = ({ ...rest }: any) => {
}) })
); );
} }
} }}
}} onKeyDown={(e: any) => {
> if (e.key === ' ' || e.key === 'Enter') {
{d.title} e.preventDefault();
</StyledTagLink> if (!rest.isModal) {
); history.push(`/library/artist/${d.id}`);
})} } else {
{data.genre.map((d: Genre) => { dispatch(
return ( addModalPage({
<StyledTagLink pageType: 'artist',
key={nanoid()} id: d.id,
tabIndex={0} })
tooltip={d.title} );
onClick={() => { }
if (!rest.isModal) {
dispatch(setActive({ ...album.active, filter: d.title }));
setTimeout(() => {
history.push(`/library/album?sortType=${d.title}`);
}, 50);
}
}}
onKeyDown={(e: any) => {
if (e.key === ' ' || e.key === 'Enter') {
e.preventDefault();
if (!rest.isModal) {
dispatch(setActive({ ...album.active, filter: d.title }));
setTimeout(() => {
history.push(`/library/album?sortType=${d.title}`);
}, 50);
} }
} }}
}} >
> {d.title}
{d.title} </StyledTagLink>
</StyledTagLink> );
); })
})} ) : (
<span>&#8203;</span>
)}
</PageHeaderSubtitleDataLine> </PageHeaderSubtitleDataLine>
<div style={{ marginTop: '10px' }}> <div style={{ marginTop: '10px' }}>
<ButtonToolbar> <ButtonToolbar>
@ -445,7 +501,7 @@ const AlbumView = ({ ...rest }: any) => {
> >
<ListViewType <ListViewType
data={misc.searchQuery !== '' ? filteredData : data.song} data={misc.searchQuery !== '' ? filteredData : data.song}
tableColumns={settings.getSync('musicListColumns')} tableColumns={config.lookAndFeel.listView.music.columns}
handleRowClick={handleRowClick} handleRowClick={handleRowClick}
handleRowDoubleClick={handleRowDoubleClick} handleRowDoubleClick={handleRowDoubleClick}
handleRating={handleRowRating} handleRating={handleRowRating}

16
src/components/shared/styled.ts

@ -470,13 +470,23 @@ export const SectionTitle = styled.a`
} }
`; `;
export const StyledLink = styled.a` export const LinkWrapper = styled.span<{ maxWidth: string }>`
display: inline-block;
max-width: ${(props) => props.maxWidth};
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
vertical-align: bottom;
`;
export const StyledLink = styled.a<{ underline?: boolean }>`
color: ${(props) => props.theme.colors.layout.page.color}; color: ${(props) => props.theme.colors.layout.page.color};
cursor: pointer; cursor: pointer;
text-decoration: underline; text-decoration: ${(props) => (props.underline ? 'underline' : undefined)};
font-weight: bold;
&:hover { &:hover {
color: ${(props) => props.theme.colors.button.link.colorHover}; color: ${(props) => props.theme.colors.layout.page.color};
} }
&:focus-visible { &:focus-visible {

Loading…
Cancel
Save