mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-09 20:29:36 +02:00
support playlist sidebar drag to queue
This commit is contained in:
@@ -15,6 +15,11 @@ export const SidebarItem = ({ children, className, to, ...props }: SidebarItemPr
|
|||||||
const toPath = typeof to === 'string' ? to : to.pathname || '';
|
const toPath = typeof to === 'string' ? to : to.pathname || '';
|
||||||
const isActive = location.pathname === toPath;
|
const isActive = location.pathname === toPath;
|
||||||
|
|
||||||
|
const handleLinkDragStart = (e: React.DragEvent<HTMLButtonElement>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
className={clsx(
|
className={clsx(
|
||||||
@@ -31,6 +36,8 @@ export const SidebarItem = ({ children, className, to, ...props }: SidebarItemPr
|
|||||||
label: styles.label,
|
label: styles.label,
|
||||||
}}
|
}}
|
||||||
component={Link}
|
component={Link}
|
||||||
|
draggable={false}
|
||||||
|
onDragStart={handleLinkDragStart}
|
||||||
to={to}
|
to={to}
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import { generatePath, Link } from 'react-router';
|
|||||||
|
|
||||||
import styles from './sidebar-playlist-list.module.css';
|
import styles from './sidebar-playlist-list.module.css';
|
||||||
|
|
||||||
|
import { getDraggedItems } from '/@/renderer/components/item-list/helpers/get-dragged-items';
|
||||||
|
import { ContextMenuController } from '/@/renderer/features/context-menu/context-menu-controller';
|
||||||
import { usePlayer } from '/@/renderer/features/player/context/player-context';
|
import { usePlayer } from '/@/renderer/features/player/context/player-context';
|
||||||
import { playlistsQueries } from '/@/renderer/features/playlists/api/playlists-api';
|
import { playlistsQueries } from '/@/renderer/features/playlists/api/playlists-api';
|
||||||
import { CreatePlaylistForm } from '/@/renderer/features/playlists/components/create-playlist-form';
|
import { CreatePlaylistForm } from '/@/renderer/features/playlists/components/create-playlist-form';
|
||||||
@@ -30,19 +32,34 @@ import {
|
|||||||
import { DragOperation, DragTarget } from '/@/shared/types/drag-and-drop';
|
import { DragOperation, DragTarget } from '/@/shared/types/drag-and-drop';
|
||||||
import { Play } from '/@/shared/types/types';
|
import { Play } from '/@/shared/types/types';
|
||||||
|
|
||||||
interface PlaylistRowButtonProps extends Omit<ButtonProps, 'onPlay'> {
|
interface PlaylistRowButtonProps extends Omit<ButtonProps, 'onContextMenu' | 'onPlay'> {
|
||||||
|
item: Playlist;
|
||||||
name: string;
|
name: string;
|
||||||
|
onContextMenu: (e: MouseEvent<HTMLButtonElement>, item: Playlist) => void;
|
||||||
onPlay: (id: string, playType: Play) => void;
|
onPlay: (id: string, playType: Play) => void;
|
||||||
to: string;
|
to: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PlaylistRowButton = ({ name, onPlay, to, ...props }: PlaylistRowButtonProps) => {
|
const PlaylistRowButton = ({ item, name, onContextMenu, onPlay, to }: PlaylistRowButtonProps) => {
|
||||||
const url = generatePath(AppRoute.PLAYLISTS_DETAIL_SONGS, { playlistId: to });
|
const url = generatePath(AppRoute.PLAYLISTS_DETAIL_SONGS, { playlistId: to });
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
|
|
||||||
const { isDraggedOver, ref } = useDragDrop<HTMLDivElement>({
|
const { isDraggedOver, isDragging, ref } = useDragDrop<HTMLDivElement>({
|
||||||
|
drag: {
|
||||||
|
getId: () => {
|
||||||
|
const draggedItems = getDraggedItems(item, undefined);
|
||||||
|
return draggedItems.map((draggedItem) => draggedItem.id);
|
||||||
|
},
|
||||||
|
getItem: () => {
|
||||||
|
const draggedItems = getDraggedItems(item, undefined);
|
||||||
|
return draggedItems;
|
||||||
|
},
|
||||||
|
itemType: LibraryItem.PLAYLIST,
|
||||||
|
operation: [DragOperation.ADD],
|
||||||
|
target: DragTarget.PLAYLIST,
|
||||||
|
},
|
||||||
drop: {
|
drop: {
|
||||||
canDrop: (args) => {
|
canDrop: (args) => {
|
||||||
return (
|
return (
|
||||||
@@ -127,14 +144,17 @@ const PlaylistRowButton = ({ name, onPlay, to, ...props }: PlaylistRowButtonProp
|
|||||||
onMouseEnter={() => setIsHovered(true)}
|
onMouseEnter={() => setIsHovered(true)}
|
||||||
onMouseLeave={() => setIsHovered(false)}
|
onMouseLeave={() => setIsHovered(false)}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
style={{
|
||||||
|
opacity: isDragging ? 0.5 : 1,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<SidebarItem
|
<SidebarItem
|
||||||
className={clsx({
|
className={clsx({
|
||||||
[styles.rowHover]: isHovered,
|
[styles.rowHover]: isHovered,
|
||||||
})}
|
})}
|
||||||
|
onContextMenu={(e) => onContextMenu(e, item)}
|
||||||
to={url}
|
to={url}
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
{...props}
|
|
||||||
>
|
>
|
||||||
{name}
|
{name}
|
||||||
</SidebarItem>
|
</SidebarItem>
|
||||||
@@ -241,6 +261,17 @@ export const SidebarPlaylistList = () => {
|
|||||||
[player, server.id],
|
[player, server.id],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleContextMenu = useCallback(
|
||||||
|
(e: MouseEvent<HTMLButtonElement>, playlist: Playlist) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
ContextMenuController.call({
|
||||||
|
cmd: { items: [playlist], type: LibraryItem.PLAYLIST },
|
||||||
|
event: e,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
const memoizedItemData = useMemo(() => {
|
const memoizedItemData = useMemo(() => {
|
||||||
const base = { handlePlay: handlePlayPlaylist };
|
const base = { handlePlay: handlePlayPlaylist };
|
||||||
|
|
||||||
@@ -317,8 +348,10 @@ export const SidebarPlaylistList = () => {
|
|||||||
<Accordion.Panel>
|
<Accordion.Panel>
|
||||||
{memoizedItemData?.items?.map((item, index) => (
|
{memoizedItemData?.items?.map((item, index) => (
|
||||||
<PlaylistRowButton
|
<PlaylistRowButton
|
||||||
|
item={item}
|
||||||
key={index}
|
key={index}
|
||||||
name={item.name}
|
name={item.name}
|
||||||
|
onContextMenu={handleContextMenu}
|
||||||
onPlay={handlePlayPlaylist}
|
onPlay={handlePlayPlaylist}
|
||||||
to={item.id}
|
to={item.id}
|
||||||
/>
|
/>
|
||||||
@@ -352,6 +385,20 @@ export const SidebarSharedPlaylistList = () => {
|
|||||||
[player, server.id],
|
[player, server.id],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleContextMenu = useCallback(
|
||||||
|
(e: MouseEvent<HTMLButtonElement>, playlist: Playlist) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
ContextMenuController.call({
|
||||||
|
cmd: {
|
||||||
|
items: [playlist],
|
||||||
|
type: LibraryItem.PLAYLIST,
|
||||||
|
},
|
||||||
|
event: e,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
const memoizedItemData = useMemo(() => {
|
const memoizedItemData = useMemo(() => {
|
||||||
const base = { handlePlay: handlePlayPlaylist };
|
const base = { handlePlay: handlePlayPlaylist };
|
||||||
|
|
||||||
@@ -386,8 +433,10 @@ export const SidebarSharedPlaylistList = () => {
|
|||||||
<Accordion.Panel>
|
<Accordion.Panel>
|
||||||
{memoizedItemData?.items?.map((item, index) => (
|
{memoizedItemData?.items?.map((item, index) => (
|
||||||
<PlaylistRowButton
|
<PlaylistRowButton
|
||||||
|
item={item}
|
||||||
key={index}
|
key={index}
|
||||||
name={item.name}
|
name={item.name}
|
||||||
|
onContextMenu={handleContextMenu}
|
||||||
onPlay={handlePlayPlaylist}
|
onPlay={handlePlayPlaylist}
|
||||||
to={item.id}
|
to={item.id}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user