diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json
index 8693bf5a..20e066e4 100644
--- a/src/i18n/locales/en.json
+++ b/src/i18n/locales/en.json
@@ -364,6 +364,8 @@
"setRating": "$t(action.setRating)",
"playShuffled": "$t(player.shuffle)",
"shareItem": "share item",
+ "goToAlbum": "go to $t(entity.album_one)",
+ "goToAlbumArtist": "go to $t(entity.albumArtist_one)",
"showDetails": "get info"
},
"fullscreenPlayer": {
diff --git a/src/renderer/app.tsx b/src/renderer/app.tsx
index f3f077b4..85c95774 100644
--- a/src/renderer/app.tsx
+++ b/src/renderer/app.tsx
@@ -16,7 +16,6 @@ import 'overlayscrollbars/overlayscrollbars.css';
import '/styles/overlayscrollbars.css';
import i18n from '/@/i18n/i18n';
-import { ContextMenuProvider } from '/@/renderer/features/context-menu';
import { useDiscordRpc } from '/@/renderer/features/discord-rpc/use-discord-rpc';
import { PlayQueueHandlerContext } from '/@/renderer/features/player';
import { WebAudioContext } from '/@/renderer/features/player/context/webaudio-context';
@@ -193,11 +192,9 @@ export const App = () => {
-
-
-
- {' '}
-
+
+
+
diff --git a/src/renderer/features/context-menu/context-menu-items.tsx b/src/renderer/features/context-menu/context-menu-items.tsx
index 8b5a622d..2b16572c 100644
--- a/src/renderer/features/context-menu/context-menu-items.tsx
+++ b/src/renderer/features/context-menu/context-menu-items.tsx
@@ -12,6 +12,8 @@ export const QUEUE_CONTEXT_MENU_ITEMS: SetContextMenuItems = [
{ disabled: false, divider: true, id: 'deselectAll' },
{ id: 'download' },
{ divider: true, id: 'shareItem' },
+ { id: 'goToAlbum' },
+ { id: 'goToAlbumArtist' },
{ divider: true, id: 'showDetails' },
];
@@ -27,6 +29,8 @@ export const SONG_CONTEXT_MENU_ITEMS: SetContextMenuItems = [
{ children: true, disabled: false, divider: true, id: 'setRating' },
{ id: 'download' },
{ divider: true, id: 'shareItem' },
+ { id: 'goToAlbum' },
+ { id: 'goToAlbumArtist' },
{ divider: true, id: 'showDetails' },
];
@@ -51,6 +55,8 @@ export const PLAYLIST_SONG_CONTEXT_MENU_ITEMS: SetContextMenuItems = [
{ children: true, disabled: false, id: 'setRating' },
{ id: 'download' },
{ divider: true, id: 'shareItem' },
+ { id: 'goToAlbum' },
+ { id: 'goToAlbumArtist' },
{ divider: true, id: 'showDetails' },
];
@@ -66,6 +72,8 @@ export const SMART_PLAYLIST_SONG_CONTEXT_MENU_ITEMS: SetContextMenuItems = [
{ children: true, disabled: false, id: 'setRating' },
{ id: 'download' },
{ divider: true, id: 'shareItem' },
+ { id: 'goToAlbum' },
+ { id: 'goToAlbumArtist' },
{ divider: true, id: 'showDetails' },
];
@@ -79,6 +87,7 @@ export const ALBUM_CONTEXT_MENU_ITEMS: SetContextMenuItems = [
{ id: 'removeFromFavorites' },
{ children: true, disabled: false, divider: true, id: 'setRating' },
{ divider: true, id: 'shareItem' },
+ { id: 'goToAlbumArtist' },
{ divider: true, id: 'showDetails' },
];
diff --git a/src/renderer/features/context-menu/context-menu-provider.tsx b/src/renderer/features/context-menu/context-menu-provider.tsx
index a294eb6b..39732b44 100644
--- a/src/renderer/features/context-menu/context-menu-provider.tsx
+++ b/src/renderer/features/context-menu/context-menu-provider.tsx
@@ -19,6 +19,7 @@ import {
useState,
} from 'react';
import { useTranslation } from 'react-i18next';
+import { generatePath, useNavigate } from 'react-router-dom';
import { api } from '/@/renderer/api';
import { controller } from '/@/renderer/api/controller';
@@ -34,6 +35,7 @@ import { updateSong } from '/@/renderer/features/player/update-remote-song';
import { useDeletePlaylist } from '/@/renderer/features/playlists';
import { useRemoveFromPlaylist } from '/@/renderer/features/playlists/mutations/remove-from-playlist-mutation';
import { useCreateFavorite, useDeleteFavorite, useSetRating } from '/@/renderer/features/shared';
+import { AppRoute } from '/@/renderer/router/routes';
import {
getServerById,
useAuthStore,
@@ -131,6 +133,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
});
const handlePlayQueueAdd = usePlayQueueAdd();
+ const navigate = useNavigate();
const openContextMenu = useCallback(
(args: OpenContextMenuProps) => {
@@ -734,6 +737,24 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
}
}, [ctx.data, server]);
+ const handleGoToAlbum = useCallback(() => {
+ const item = ctx.data[0];
+ if (item.albumId) {
+ navigate(generatePath(AppRoute.LIBRARY_ALBUMS_DETAIL, { albumId: item.albumId }));
+ }
+ }, [ctx.data, navigate]);
+
+ const handleGoToAlbumArtist = useCallback(() => {
+ const item = ctx.data[0];
+ if (item.albumArtists && item.albumArtists.length > 0) {
+ navigate(
+ generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL, {
+ albumArtistId: item.albumArtists[0].id,
+ }),
+ );
+ }
+ }, [ctx.data, navigate]);
+
const contextMenuItems: Record = useMemo(() => {
return {
addToFavorites: {
@@ -772,6 +793,23 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
leftIcon: ,
onClick: handleDownload,
},
+ goToAlbum: {
+ disabled: ctx.data?.length !== 1 || !ctx.data[0]?.albumId,
+ id: 'goToAlbum',
+ label: t('page.contextMenu.goToAlbum', { postProcess: 'sentenceCase' }),
+ leftIcon: ,
+ onClick: handleGoToAlbum,
+ },
+ goToAlbumArtist: {
+ disabled:
+ ctx.data?.length !== 1 ||
+ !ctx.data[0]?.albumArtists ||
+ ctx.data[0]?.albumArtists?.length === 0,
+ id: 'goToAlbumArtist',
+ label: t('page.contextMenu.goToAlbumArtist', { postProcess: 'sentenceCase' }),
+ leftIcon: ,
+ onClick: handleGoToAlbumArtist,
+ },
moveToBottomOfQueue: {
id: 'moveToBottomOfQueue',
label: t('page.contextMenu.moveToBottom', { postProcess: 'sentenceCase' }),
@@ -888,6 +926,8 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
handleRemoveSelected,
server,
handleShareItem,
+ handleGoToAlbum,
+ handleGoToAlbumArtist,
handleOpenItemDetails,
handlePlay,
handleUpdateRating,
diff --git a/src/renderer/features/context-menu/events.ts b/src/renderer/features/context-menu/events.ts
index 28529c17..6165ea13 100644
--- a/src/renderer/features/context-menu/events.ts
+++ b/src/renderer/features/context-menu/events.ts
@@ -15,6 +15,8 @@ export type ContextMenuItemType =
| 'deletePlaylist'
| 'deselectAll'
| 'download'
+ | 'goToAlbum'
+ | 'goToAlbumArtist'
| 'moveToBottomOfQueue'
| 'moveToNextOfQueue'
| 'moveToTopOfQueue'
@@ -57,6 +59,8 @@ export const CONFIGURABLE_CONTEXT_MENU_ITEMS: ContextMenuItemType[] = [
'setRating',
'download',
'shareItem',
+ 'goToAlbum',
+ 'goToAlbumArtist',
'showDetails',
];
diff --git a/src/renderer/layouts/default-layout.tsx b/src/renderer/layouts/default-layout.tsx
index 7473776d..846057fa 100644
--- a/src/renderer/layouts/default-layout.tsx
+++ b/src/renderer/layouts/default-layout.tsx
@@ -6,6 +6,7 @@ import { useNavigate } from 'react-router';
import styles from './default-layout.module.css';
+import { ContextMenuProvider } from '/@/renderer/features/context-menu';
import { CommandPalette } from '/@/renderer/features/search/components/command-palette';
import { MainContent } from '/@/renderer/layouts/default-layout/main-content';
import { PlayerBar } from '/@/renderer/layouts/default-layout/player-bar';
@@ -73,7 +74,7 @@ export const DefaultLayout = ({ shell }: DefaultLayoutProps) => {
]);
return (
- <>
+
- >
+
);
};