mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-09 20:29:36 +02:00
move genre buttons to album detail header
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { Suspense, useMemo, useState } from 'react';
|
import { Suspense, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { generatePath, Link, useParams } from 'react-router';
|
import { useParams } from 'react-router';
|
||||||
|
|
||||||
import styles from './album-detail-content.module.css';
|
import styles from './album-detail-content.module.css';
|
||||||
|
|
||||||
@@ -19,7 +19,6 @@ import { ListConfigMenu } from '/@/renderer/features/shared/components/list-conf
|
|||||||
import { PlayButton } from '/@/renderer/features/shared/components/play-button';
|
import { PlayButton } from '/@/renderer/features/shared/components/play-button';
|
||||||
import { searchLibraryItems } from '/@/renderer/features/shared/utils';
|
import { searchLibraryItems } from '/@/renderer/features/shared/utils';
|
||||||
import { useContainerQuery } from '/@/renderer/hooks';
|
import { useContainerQuery } from '/@/renderer/hooks';
|
||||||
import { useGenreRoute } from '/@/renderer/hooks/use-genre-route';
|
|
||||||
import { useCurrentServer } from '/@/renderer/store';
|
import { useCurrentServer } from '/@/renderer/store';
|
||||||
import {
|
import {
|
||||||
useGeneralSettings,
|
useGeneralSettings,
|
||||||
@@ -28,7 +27,6 @@ import {
|
|||||||
} from '/@/renderer/store/settings.store';
|
} from '/@/renderer/store/settings.store';
|
||||||
import { replaceURLWithHTMLLinks } from '/@/renderer/utils/linkify';
|
import { replaceURLWithHTMLLinks } from '/@/renderer/utils/linkify';
|
||||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||||
import { Button } from '/@/shared/components/button/button';
|
|
||||||
import { Checkbox } from '/@/shared/components/checkbox/checkbox';
|
import { Checkbox } from '/@/shared/components/checkbox/checkbox';
|
||||||
import { Group } from '/@/shared/components/group/group';
|
import { Group } from '/@/shared/components/group/group';
|
||||||
import { Icon } from '/@/shared/components/icon/icon';
|
import { Icon } from '/@/shared/components/icon/icon';
|
||||||
@@ -54,7 +52,6 @@ export const AlbumDetailContent = ({ background }: AlbumDetailContentProps) => {
|
|||||||
|
|
||||||
const { ref, ...cq } = useContainerQuery();
|
const { ref, ...cq } = useContainerQuery();
|
||||||
const { externalLinks, lastFM, musicBrainz } = useGeneralSettings();
|
const { externalLinks, lastFM, musicBrainz } = useGeneralSettings();
|
||||||
const genreRoute = useGenreRoute();
|
|
||||||
|
|
||||||
const carousels = [
|
const carousels = [
|
||||||
{
|
{
|
||||||
@@ -94,23 +91,13 @@ export const AlbumDetailContent = ({ background }: AlbumDetailContentProps) => {
|
|||||||
];
|
];
|
||||||
const playButtonBehavior = usePlayButtonBehavior();
|
const playButtonBehavior = usePlayButtonBehavior();
|
||||||
|
|
||||||
const { addToQueueByFetch, setFavorite } = usePlayer();
|
const { addToQueueByFetch } = usePlayer();
|
||||||
|
|
||||||
const handlePlay = () => {
|
const handlePlay = () => {
|
||||||
if (!server?.id) return;
|
if (!server?.id) return;
|
||||||
addToQueueByFetch(server.id, [albumId], LibraryItem.ALBUM, playButtonBehavior);
|
addToQueueByFetch(server.id, [albumId], LibraryItem.ALBUM, playButtonBehavior);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFavorite = () => {
|
|
||||||
if (!detailQuery?.data) return;
|
|
||||||
setFavorite(
|
|
||||||
detailQuery.data._serverId,
|
|
||||||
[detailQuery.data.id],
|
|
||||||
LibraryItem.ALBUM,
|
|
||||||
!detailQuery.data.userFavorite,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMoreOptions = (e: React.MouseEvent<HTMLButtonElement>) => {
|
const handleMoreOptions = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
if (!detailQuery?.data) return;
|
if (!detailQuery?.data) return;
|
||||||
ContextMenuController.call({
|
ContextMenuController.call({
|
||||||
@@ -119,7 +106,6 @@ export const AlbumDetailContent = ({ background }: AlbumDetailContentProps) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const showGenres = detailQuery?.data?.genres ? detailQuery?.data?.genres.length !== 0 : false;
|
|
||||||
const comment = detailQuery?.data?.comment;
|
const comment = detailQuery?.data?.comment;
|
||||||
|
|
||||||
const mbzId = detailQuery?.data?.mbzId;
|
const mbzId = detailQuery?.data?.mbzId;
|
||||||
@@ -132,48 +118,15 @@ export const AlbumDetailContent = ({ background }: AlbumDetailContentProps) => {
|
|||||||
<Group gap="sm" justify="space-between">
|
<Group gap="sm" justify="space-between">
|
||||||
<Group>
|
<Group>
|
||||||
<PlayButton onClick={handlePlay} />
|
<PlayButton onClick={handlePlay} />
|
||||||
<Group gap="xs">
|
<ActionIcon
|
||||||
<ActionIcon
|
icon="ellipsisHorizontal"
|
||||||
icon="favorite"
|
onClick={handleMoreOptions}
|
||||||
iconProps={{
|
size="lg"
|
||||||
fill: detailQuery?.data?.userFavorite
|
variant="transparent"
|
||||||
? 'primary'
|
/>
|
||||||
: undefined,
|
|
||||||
}}
|
|
||||||
onClick={handleFavorite}
|
|
||||||
size="lg"
|
|
||||||
variant="transparent"
|
|
||||||
/>
|
|
||||||
<ActionIcon
|
|
||||||
icon="ellipsisHorizontal"
|
|
||||||
onClick={handleMoreOptions}
|
|
||||||
size="lg"
|
|
||||||
variant="transparent"
|
|
||||||
/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</section>
|
</section>
|
||||||
{showGenres && (
|
|
||||||
<section>
|
|
||||||
<Group gap="sm">
|
|
||||||
{detailQuery?.data?.genres?.map((genre) => (
|
|
||||||
<Button
|
|
||||||
component={Link}
|
|
||||||
key={`genre-${genre.id}`}
|
|
||||||
radius="md"
|
|
||||||
size="compact-md"
|
|
||||||
to={generatePath(genreRoute, {
|
|
||||||
genreId: genre.id,
|
|
||||||
})}
|
|
||||||
variant="outline"
|
|
||||||
>
|
|
||||||
{genre.name}
|
|
||||||
</Button>
|
|
||||||
))}
|
|
||||||
</Group>
|
|
||||||
</section>
|
|
||||||
)}
|
|
||||||
{externalLinks && (lastFM || musicBrainz) ? (
|
{externalLinks && (lastFM || musicBrainz) ? (
|
||||||
<section>
|
<section>
|
||||||
<Group gap="sm">
|
<Group gap="sm">
|
||||||
@@ -435,6 +388,12 @@ const AlbumDetailSongsTable = ({ songs }: AlbumDetailSongsTableProps) => {
|
|||||||
/>
|
/>
|
||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
|
styles={{
|
||||||
|
input: {
|
||||||
|
background: 'transparent',
|
||||||
|
border: '1px solid rgba(255, 255, 255, 0.05)',
|
||||||
|
},
|
||||||
|
}}
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
/>
|
/>
|
||||||
<ListConfigMenu
|
<ListConfigMenu
|
||||||
|
|||||||
@@ -6,10 +6,13 @@ import { generatePath, Link, useParams } from 'react-router';
|
|||||||
import { albumQueries } from '/@/renderer/features/albums/api/album-api';
|
import { albumQueries } from '/@/renderer/features/albums/api/album-api';
|
||||||
import { usePlayer } from '/@/renderer/features/player/context/player-context';
|
import { usePlayer } from '/@/renderer/features/player/context/player-context';
|
||||||
import { LibraryHeader } from '/@/renderer/features/shared/components/library-header';
|
import { LibraryHeader } from '/@/renderer/features/shared/components/library-header';
|
||||||
|
import { useGenreRoute } from '/@/renderer/hooks/use-genre-route';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import { useCurrentServer } from '/@/renderer/store';
|
import { useCurrentServer } from '/@/renderer/store';
|
||||||
import { formatDateAbsoluteUTC, formatDurationString, titleCase } from '/@/renderer/utils';
|
import { formatDateAbsoluteUTC, formatDurationString, titleCase } from '/@/renderer/utils';
|
||||||
import { normalizeReleaseTypes } from '/@/renderer/utils/normalize-release-types';
|
import { normalizeReleaseTypes } from '/@/renderer/utils/normalize-release-types';
|
||||||
|
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||||
|
import { Button } from '/@/shared/components/button/button';
|
||||||
import { Group } from '/@/shared/components/group/group';
|
import { Group } from '/@/shared/components/group/group';
|
||||||
import { Pill } from '/@/shared/components/pill/pill';
|
import { Pill } from '/@/shared/components/pill/pill';
|
||||||
import { Rating } from '/@/shared/components/rating/rating';
|
import { Rating } from '/@/shared/components/rating/rating';
|
||||||
@@ -33,11 +36,16 @@ export const AlbumDetailHeader = forwardRef<HTMLDivElement, AlbumDetailHeaderPro
|
|||||||
albumQueries.detail({ query: { id: albumId }, serverId: server?.id }),
|
albumQueries.detail({ query: { id: albumId }, serverId: server?.id }),
|
||||||
);
|
);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const genreRoute = useGenreRoute();
|
||||||
|
|
||||||
const showRating =
|
const showRating =
|
||||||
detailQuery?.data?._serverType === ServerType.NAVIDROME ||
|
detailQuery?.data?._serverType === ServerType.NAVIDROME ||
|
||||||
detailQuery?.data?._serverType === ServerType.SUBSONIC;
|
detailQuery?.data?._serverType === ServerType.SUBSONIC;
|
||||||
|
|
||||||
|
const showGenres = detailQuery?.data?.genres
|
||||||
|
? detailQuery?.data?.genres.length !== 0
|
||||||
|
: false;
|
||||||
|
|
||||||
const originalDifferentFromRelease =
|
const originalDifferentFromRelease =
|
||||||
detailQuery.data?.originalDate &&
|
detailQuery.data?.originalDate &&
|
||||||
detailQuery.data.originalDate !== detailQuery.data.releaseDate;
|
detailQuery.data.originalDate !== detailQuery.data.releaseDate;
|
||||||
@@ -95,7 +103,17 @@ export const AlbumDetailHeader = forwardRef<HTMLDivElement, AlbumDetailHeaderPro
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { setRating } = usePlayer();
|
const { setFavorite, setRating } = usePlayer();
|
||||||
|
|
||||||
|
const handleFavorite = () => {
|
||||||
|
if (!detailQuery?.data) return;
|
||||||
|
setFavorite(
|
||||||
|
detailQuery.data._serverId,
|
||||||
|
[detailQuery.data.id],
|
||||||
|
LibraryItem.ALBUM,
|
||||||
|
!detailQuery.data.userFavorite,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const handleUpdateRating = (rating: number) => {
|
const handleUpdateRating = (rating: number) => {
|
||||||
if (!detailQuery?.data) return;
|
if (!detailQuery?.data) return;
|
||||||
@@ -133,13 +151,48 @@ export const AlbumDetailHeader = forwardRef<HTMLDivElement, AlbumDetailHeaderPro
|
|||||||
),
|
),
|
||||||
)}
|
)}
|
||||||
</Pill.Group>
|
</Pill.Group>
|
||||||
{showRating && (
|
{showGenres && (
|
||||||
<Rating
|
<Group gap="sm">
|
||||||
onChange={handleUpdateRating}
|
{detailQuery?.data?.genres?.map((genre) => (
|
||||||
readOnly={detailQuery?.isFetching}
|
<Button
|
||||||
value={detailQuery?.data?.userRating || 0}
|
component={Link}
|
||||||
/>
|
key={`genre-${genre.id}`}
|
||||||
|
radius="md"
|
||||||
|
size="compact-md"
|
||||||
|
to={generatePath(genreRoute, {
|
||||||
|
genreId: genre.id,
|
||||||
|
})}
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
{genre.name}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</Group>
|
||||||
)}
|
)}
|
||||||
|
<Group align="center" gap="sm">
|
||||||
|
<ActionIcon
|
||||||
|
icon="favorite"
|
||||||
|
iconProps={{
|
||||||
|
fill: detailQuery?.data?.userFavorite ? 'primary' : undefined,
|
||||||
|
size: 'lg',
|
||||||
|
}}
|
||||||
|
onClick={handleFavorite}
|
||||||
|
size="xs"
|
||||||
|
variant="transparent"
|
||||||
|
/>
|
||||||
|
{showRating && (
|
||||||
|
<Rating
|
||||||
|
onChange={handleUpdateRating}
|
||||||
|
readOnly={detailQuery?.isFetching}
|
||||||
|
styles={{
|
||||||
|
input: {
|
||||||
|
background: 'transparent',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
value={detailQuery?.data?.userRating || 0}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Group>
|
||||||
<Group
|
<Group
|
||||||
gap="md"
|
gap="md"
|
||||||
mah="4rem"
|
mah="4rem"
|
||||||
|
|||||||
Reference in New Issue
Block a user