mirror of
https://github.com/antebudimir/feishin.git
synced 2026-01-01 10:23:33 +00:00
Redesign sidebar / header and other misc. improvements (#24)
* Remove 1920px max width * Fix position of list controls menu * Match size and color of search input * Adjust library header sizing * Move app menu to sidebar * Increase row buffer on play queue list * Fix query builder styles * Fix playerbar slider track bg * Adjust titlebar styles * Fix invalid modal prop * Various adjustments to detail pages * Fix sidebar height calculation * Fix list null indicators, add filter indicator * Adjust playqueue styles * Fix jellyfin releaseYear normalization * Suppress browser context menu on ag-grid * Add radius to drawer queue -- normalize layout * Add modal styles to provider theme * Fix playlist song list pagination * Add disc number to albums with more than one disc * Fix query builder boolean values * Adjust input placeholder color * Properly handle rating/favorite from context menu on table * Conform dropdown menu styles to context menu * Increase sort type select width * Fix drawer queue radius * Change primary color * Prevent volume wheel from invalid values * Add icons to query builder dropdowns * Update notification styles * Update scrollbar thumb styles * Remove "add to playlist" on smart playlists * Fix "add to playlist" from context menu
This commit is contained in:
parent
d2c0d4c11f
commit
9f2e873366
80 changed files with 1427 additions and 1101 deletions
|
|
@ -21,6 +21,16 @@ export const PLAYLIST_SONG_CONTEXT_MENU_ITEMS: SetContextMenuItems = [
|
|||
{ children: true, disabled: false, id: 'setRating' },
|
||||
];
|
||||
|
||||
export const SMART_PLAYLIST_SONG_CONTEXT_MENU_ITEMS: SetContextMenuItems = [
|
||||
{ id: 'play' },
|
||||
{ id: 'playLast' },
|
||||
{ divider: true, id: 'playNext' },
|
||||
{ divider: true, id: 'addToPlaylist' },
|
||||
{ id: 'addToFavorites' },
|
||||
{ divider: true, id: 'removeFromFavorites' },
|
||||
{ children: true, disabled: false, id: 'setRating' },
|
||||
];
|
||||
|
||||
export const ALBUM_CONTEXT_MENU_ITEMS: SetContextMenuItems = [
|
||||
{ id: 'play' },
|
||||
{ id: 'playLast' },
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ import { usePlayQueueAdd } from '/@/renderer/features/player';
|
|||
import { useDeletePlaylist } from '/@/renderer/features/playlists';
|
||||
import { useRemoveFromPlaylist } from '/@/renderer/features/playlists/mutations/remove-from-playlist-mutation';
|
||||
import { useCreateFavorite, useDeleteFavorite, useUpdateRating } from '/@/renderer/features/shared';
|
||||
import { useCurrentServer } from '/@/renderer/store';
|
||||
import { useAuthStore, useCurrentServer } from '/@/renderer/store';
|
||||
import { Play } from '/@/renderer/types';
|
||||
|
||||
type ContextMenuContextProps = {
|
||||
|
|
@ -65,6 +65,10 @@ const ContextMenuContext = createContext<ContextMenuContextProps>({
|
|||
},
|
||||
});
|
||||
|
||||
const JELLYFIN_IGNORED_MENU_ITEMS: ContextMenuItemType[] = ['setRating'];
|
||||
// const NAVIDROME_IGNORED_MENU_ITEMS: ContextMenuItemType[] = [];
|
||||
// const SUBSONIC_IGNORED_MENU_ITEMS: ContextMenuItemType[] = [];
|
||||
|
||||
export interface ContextMenuProviderProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
|
@ -92,6 +96,13 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||
const openContextMenu = (args: OpenContextMenuProps) => {
|
||||
const { xPos, yPos, menuItems, data, type, tableRef, dataNodes, context } = args;
|
||||
|
||||
const serverType = data[0]?.serverType || useAuthStore.getState().currentServer?.type;
|
||||
let validMenuItems = menuItems;
|
||||
|
||||
if (serverType === ServerType.JELLYFIN) {
|
||||
validMenuItems = menuItems.filter((item) => !JELLYFIN_IGNORED_MENU_ITEMS.includes(item.id));
|
||||
}
|
||||
|
||||
// If the context menu dimension can't be automatically calculated, calculate it manually
|
||||
// This is a hacky way since resize observer may not automatically recalculate when not rendered
|
||||
const menuHeight = menuRect.height || (menuItems.length + 1) * 50;
|
||||
|
|
@ -107,7 +118,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||
context,
|
||||
data,
|
||||
dataNodes,
|
||||
menuItems,
|
||||
menuItems: validMenuItems,
|
||||
tableRef,
|
||||
type,
|
||||
xPos: calculatedXPos,
|
||||
|
|
@ -187,8 +198,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||
},
|
||||
onSuccess: () => {
|
||||
toast.success({
|
||||
message: `${item.name} was successfully deleted`,
|
||||
title: 'Playlist deleted',
|
||||
message: `Playlist has been deleted`,
|
||||
});
|
||||
},
|
||||
},
|
||||
|
|
@ -269,9 +279,9 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||
let nodesToUnfavorite: RowNode<any>[] = [];
|
||||
|
||||
if (ctx.dataNodes) {
|
||||
nodesToUnfavorite = ctx.dataNodes.filter((item) => !item.data.userFavorite);
|
||||
nodesToUnfavorite = ctx.dataNodes.filter((item) => item.data.userFavorite);
|
||||
} else {
|
||||
itemsToUnfavorite = ctx.data.filter((item) => !item.userFavorite);
|
||||
itemsToUnfavorite = ctx.data.filter((item) => item.userFavorite);
|
||||
}
|
||||
|
||||
const idsToUnfavorite = nodesToUnfavorite
|
||||
|
|
@ -304,7 +314,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||
|
||||
if (ctx.dataNodes) {
|
||||
for (const node of ctx.dataNodes) {
|
||||
switch (node.data.type) {
|
||||
switch (node.data.itemType) {
|
||||
case LibraryItem.ALBUM:
|
||||
albumId.push(node.data.id);
|
||||
break;
|
||||
|
|
@ -318,7 +328,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||
}
|
||||
} else {
|
||||
for (const item of ctx.data) {
|
||||
switch (item.type) {
|
||||
switch (item.itemType) {
|
||||
case LibraryItem.ALBUM:
|
||||
albumId.push(item.id);
|
||||
break;
|
||||
|
|
@ -370,7 +380,6 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||
onSuccess: () => {
|
||||
toast.success({
|
||||
message: `${songId.length} song(s) were removed from the playlist`,
|
||||
title: 'Song(s) removed from playlist',
|
||||
});
|
||||
ctx.context?.tableRef?.current?.api?.refreshInfiniteCache();
|
||||
closeAllModals();
|
||||
|
|
@ -432,13 +441,24 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||
items = ctx.data.filter((item) => item.serverId === serverId);
|
||||
}
|
||||
|
||||
updateRatingMutation.mutate({
|
||||
_serverId: serverId,
|
||||
query: {
|
||||
item: items,
|
||||
rating,
|
||||
updateRatingMutation.mutate(
|
||||
{
|
||||
_serverId: serverId,
|
||||
query: {
|
||||
item: items,
|
||||
rating,
|
||||
},
|
||||
},
|
||||
});
|
||||
{
|
||||
onSuccess: () => {
|
||||
if (ctx.dataNodes) {
|
||||
for (const node of ctx.dataNodes) {
|
||||
node.setData({ ...node.data, userRating: rating });
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
[ctx.data, ctx.dataNodes, updateRatingMutation],
|
||||
|
|
@ -625,17 +645,15 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||
<HoverCard.Dropdown>
|
||||
<Stack spacing={0}>
|
||||
{contextMenuItems[item.id].children?.map((child) => (
|
||||
<>
|
||||
<ContextMenuButton
|
||||
key={`sub-${child.id}`}
|
||||
disabled={child.disabled}
|
||||
leftIcon={child.leftIcon}
|
||||
rightIcon={child.rightIcon}
|
||||
onClick={child.onClick}
|
||||
>
|
||||
{child.label}
|
||||
</ContextMenuButton>
|
||||
</>
|
||||
<ContextMenuButton
|
||||
key={`sub-${child.id}`}
|
||||
disabled={child.disabled}
|
||||
leftIcon={child.leftIcon}
|
||||
rightIcon={child.rightIcon}
|
||||
onClick={child.onClick}
|
||||
>
|
||||
{child.label}
|
||||
</ContextMenuButton>
|
||||
))}
|
||||
</Stack>
|
||||
</HoverCard.Dropdown>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue