Folders are working aswell!!
This commit is contained in:
parent
3a13c24301
commit
9e32aa0a99
@ -251,6 +251,74 @@ export default function RekordboxReader() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreateFolder = async (name: string) => {
|
||||
const newFolder: PlaylistNode = {
|
||||
id: uuidv4(),
|
||||
name,
|
||||
type: 'folder',
|
||||
children: [],
|
||||
};
|
||||
const updatedPlaylists = [...playlists, newFolder];
|
||||
const savedPlaylists = await api.savePlaylists(updatedPlaylists);
|
||||
setPlaylists(savedPlaylists);
|
||||
};
|
||||
|
||||
const handleMovePlaylist = async (playlistName: string, targetFolderName: string | null) => {
|
||||
let updatedPlaylists = [...playlists];
|
||||
let playlistToMove: PlaylistNode | null = null;
|
||||
|
||||
// Helper function to remove playlist from its current location
|
||||
const removePlaylist = (nodes: PlaylistNode[]): PlaylistNode[] => {
|
||||
return nodes.reduce((acc: PlaylistNode[], node) => {
|
||||
if (node.name === playlistName) {
|
||||
playlistToMove = node;
|
||||
return acc;
|
||||
}
|
||||
if (node.type === 'folder' && node.children) {
|
||||
return [...acc, {
|
||||
...node,
|
||||
children: removePlaylist(node.children)
|
||||
}];
|
||||
}
|
||||
return [...acc, node];
|
||||
}, []);
|
||||
};
|
||||
|
||||
// First, remove the playlist from its current location
|
||||
updatedPlaylists = removePlaylist(updatedPlaylists);
|
||||
|
||||
if (!playlistToMove) return; // Playlist not found
|
||||
|
||||
if (targetFolderName === null) {
|
||||
// Move to root level
|
||||
updatedPlaylists.push(playlistToMove);
|
||||
} else {
|
||||
// Move to target folder
|
||||
const addToFolder = (nodes: PlaylistNode[]): PlaylistNode[] => {
|
||||
return nodes.map(node => {
|
||||
if (node.name === targetFolderName && node.type === 'folder') {
|
||||
return {
|
||||
...node,
|
||||
children: [...(node.children || []), playlistToMove!]
|
||||
};
|
||||
}
|
||||
if (node.type === 'folder' && node.children) {
|
||||
return {
|
||||
...node,
|
||||
children: addToFolder(node.children)
|
||||
};
|
||||
}
|
||||
return node;
|
||||
});
|
||||
};
|
||||
|
||||
updatedPlaylists = addToFolder(updatedPlaylists);
|
||||
}
|
||||
|
||||
const savedPlaylists = await api.savePlaylists(updatedPlaylists);
|
||||
setPlaylists(savedPlaylists);
|
||||
};
|
||||
|
||||
const displayedSongs = currentPlaylist === "All Songs"
|
||||
? songs
|
||||
: songs.filter((song: Song) => {
|
||||
@ -322,6 +390,8 @@ export default function RekordboxReader() {
|
||||
if (isMobile) onClose();
|
||||
}}
|
||||
onPlaylistDelete={handlePlaylistDelete}
|
||||
onFolderCreate={handleCreateFolder}
|
||||
onPlaylistMove={handleMovePlaylist}
|
||||
/>
|
||||
);
|
||||
|
||||
|
||||
@ -19,9 +19,12 @@ import {
|
||||
MenuItem,
|
||||
IconButton,
|
||||
Collapse,
|
||||
MenuDivider,
|
||||
MenuGroup,
|
||||
useToast
|
||||
} from "@chakra-ui/react";
|
||||
import { ChevronDownIcon, DeleteIcon, ChevronRightIcon } from "@chakra-ui/icons";
|
||||
import React, { useState } from "react";
|
||||
import { ChevronDownIcon, DeleteIcon, ChevronRightIcon, AddIcon, ViewIcon } from "@chakra-ui/icons";
|
||||
import React, { useState, useCallback } from "react";
|
||||
import { PlaylistNode } from "../types/interfaces";
|
||||
|
||||
interface PlaylistManagerProps {
|
||||
@ -30,6 +33,8 @@ interface PlaylistManagerProps {
|
||||
onPlaylistCreate: (name: string) => void;
|
||||
onPlaylistSelect: (name: string | null) => void;
|
||||
onPlaylistDelete: (name: string) => void;
|
||||
onFolderCreate: (name: string) => void;
|
||||
onPlaylistMove: (playlistName: string, targetFolderName: string | null) => void;
|
||||
}
|
||||
|
||||
const getButtonStyles = (isSelected: boolean) => ({
|
||||
@ -57,6 +62,8 @@ interface PlaylistItemProps {
|
||||
selectedItem: string | null;
|
||||
onPlaylistSelect: (name: string | null) => void;
|
||||
onPlaylistDelete: (name: string) => void;
|
||||
onPlaylistMove: (playlistName: string, targetFolderName: string | null) => void;
|
||||
allFolders: { name: string }[];
|
||||
}
|
||||
|
||||
const PlaylistItem: React.FC<PlaylistItemProps> = ({
|
||||
@ -65,9 +72,11 @@ const PlaylistItem: React.FC<PlaylistItemProps> = ({
|
||||
selectedItem,
|
||||
onPlaylistSelect,
|
||||
onPlaylistDelete,
|
||||
onPlaylistMove,
|
||||
allFolders,
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState(true);
|
||||
const indent = level * 16; // 16px indent per level
|
||||
const indent = level * 20; // Increased indent per level
|
||||
|
||||
if (node.type === 'folder') {
|
||||
return (
|
||||
@ -98,6 +107,8 @@ const PlaylistItem: React.FC<PlaylistItemProps> = ({
|
||||
selectedItem={selectedItem}
|
||||
onPlaylistSelect={onPlaylistSelect}
|
||||
onPlaylistDelete={onPlaylistDelete}
|
||||
onPlaylistMove={onPlaylistMove}
|
||||
allFolders={allFolders}
|
||||
/>
|
||||
))}
|
||||
</VStack>
|
||||
@ -127,6 +138,27 @@ const PlaylistItem: React.FC<PlaylistItemProps> = ({
|
||||
_hover={{ color: "white", bg: "whiteAlpha.200" }}
|
||||
/>
|
||||
<MenuList bg="gray.800" borderColor="gray.700">
|
||||
<MenuGroup title="Move to folder">
|
||||
<MenuItem
|
||||
bg="gray.800"
|
||||
_hover={{ bg: "gray.700" }}
|
||||
onClick={() => onPlaylistMove(node.name, null)}
|
||||
>
|
||||
Root level
|
||||
</MenuItem>
|
||||
<MenuDivider />
|
||||
{allFolders.map((folder) => (
|
||||
<MenuItem
|
||||
key={folder.name}
|
||||
bg="gray.800"
|
||||
_hover={{ bg: "gray.700" }}
|
||||
onClick={() => onPlaylistMove(node.name, folder.name)}
|
||||
>
|
||||
{folder.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</MenuGroup>
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
bg="gray.800"
|
||||
color="red.300"
|
||||
@ -148,15 +180,43 @@ export const PlaylistManager: React.FC<PlaylistManagerProps> = ({
|
||||
onPlaylistCreate,
|
||||
onPlaylistSelect,
|
||||
onPlaylistDelete,
|
||||
onFolderCreate,
|
||||
onPlaylistMove,
|
||||
}) => {
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const { isOpen: isPlaylistModalOpen, onOpen: onPlaylistModalOpen, onClose: onPlaylistModalClose } = useDisclosure();
|
||||
const { isOpen: isFolderModalOpen, onOpen: onFolderModalOpen, onClose: onFolderModalClose } = useDisclosure();
|
||||
const [newPlaylistName, setNewPlaylistName] = useState("");
|
||||
const [newFolderName, setNewFolderName] = useState("");
|
||||
|
||||
// Helper function to get all folders from the playlist tree
|
||||
const getAllFolders = useCallback((nodes: PlaylistNode[]): { name: string }[] => {
|
||||
let result: { name: string }[] = [];
|
||||
for (const node of nodes) {
|
||||
if (node.type === 'folder') {
|
||||
result.push({ name: node.name });
|
||||
if (node.children) {
|
||||
result = result.concat(getAllFolders(node.children));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}, []);
|
||||
|
||||
const allFolders = getAllFolders(playlists);
|
||||
|
||||
const handleCreatePlaylist = () => {
|
||||
if (newPlaylistName.trim()) {
|
||||
onPlaylistCreate(newPlaylistName);
|
||||
setNewPlaylistName("");
|
||||
onClose();
|
||||
onPlaylistModalClose();
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreateFolder = () => {
|
||||
if (newFolderName.trim()) {
|
||||
onFolderCreate(newFolderName);
|
||||
setNewFolderName("");
|
||||
onFolderModalClose();
|
||||
}
|
||||
};
|
||||
|
||||
@ -177,27 +237,47 @@ export const PlaylistManager: React.FC<PlaylistManagerProps> = ({
|
||||
selectedItem={selectedItem}
|
||||
onPlaylistSelect={onPlaylistSelect}
|
||||
onPlaylistDelete={onPlaylistDelete}
|
||||
onPlaylistMove={onPlaylistMove}
|
||||
allFolders={allFolders}
|
||||
/>
|
||||
))}
|
||||
</VStack>
|
||||
|
||||
<Button
|
||||
onClick={onOpen}
|
||||
colorScheme="blue"
|
||||
size="sm"
|
||||
width="100%"
|
||||
borderRadius="md"
|
||||
_hover={{
|
||||
transform: "translateY(-1px)",
|
||||
boxShadow: "sm",
|
||||
}}
|
||||
>
|
||||
Create New Playlist
|
||||
</Button>
|
||||
<Flex gap={2}>
|
||||
<Button
|
||||
onClick={onPlaylistModalOpen}
|
||||
colorScheme="blue"
|
||||
size="sm"
|
||||
flex={1}
|
||||
leftIcon={<AddIcon />}
|
||||
borderRadius="md"
|
||||
_hover={{
|
||||
transform: "translateY(-1px)",
|
||||
boxShadow: "sm",
|
||||
}}
|
||||
>
|
||||
New Playlist
|
||||
</Button>
|
||||
<Button
|
||||
onClick={onFolderModalOpen}
|
||||
colorScheme="teal"
|
||||
size="sm"
|
||||
flex={1}
|
||||
leftIcon={<ViewIcon />}
|
||||
borderRadius="md"
|
||||
_hover={{
|
||||
transform: "translateY(-1px)",
|
||||
boxShadow: "sm",
|
||||
}}
|
||||
>
|
||||
New Folder
|
||||
</Button>
|
||||
</Flex>
|
||||
|
||||
{/* New Playlist Modal */}
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onClose={onClose}
|
||||
isOpen={isPlaylistModalOpen}
|
||||
onClose={onPlaylistModalClose}
|
||||
isCentered
|
||||
motionPreset="slideInBottom"
|
||||
>
|
||||
@ -242,7 +322,67 @@ export const PlaylistManager: React.FC<PlaylistManagerProps> = ({
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={onClose}
|
||||
onClick={onPlaylistModalClose}
|
||||
color="gray.300"
|
||||
_hover={{
|
||||
bg: "whiteAlpha.200",
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
|
||||
{/* New Folder Modal */}
|
||||
<Modal
|
||||
isOpen={isFolderModalOpen}
|
||||
onClose={onFolderModalClose}
|
||||
isCentered
|
||||
motionPreset="slideInBottom"
|
||||
>
|
||||
<ModalOverlay bg="blackAlpha.700" backdropFilter="blur(5px)" />
|
||||
<ModalContent
|
||||
bg="gray.800"
|
||||
borderRadius="xl"
|
||||
boxShadow="xl"
|
||||
border="1px"
|
||||
borderColor="gray.700"
|
||||
>
|
||||
<ModalHeader color="white">Create New Folder</ModalHeader>
|
||||
<ModalCloseButton color="white" />
|
||||
<ModalBody pb={6}>
|
||||
<Input
|
||||
value={newFolderName}
|
||||
onChange={(e) => setNewFolderName(e.target.value)}
|
||||
placeholder="Enter folder name"
|
||||
bg="gray.700"
|
||||
border="none"
|
||||
color="white"
|
||||
_placeholder={{ color: "gray.400" }}
|
||||
_focus={{
|
||||
boxShadow: "0 0 0 1px teal.500",
|
||||
borderColor: "teal.500",
|
||||
}}
|
||||
/>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<Button
|
||||
colorScheme="teal"
|
||||
mr={3}
|
||||
onClick={handleCreateFolder}
|
||||
isDisabled={!newFolderName.trim()}
|
||||
_hover={{
|
||||
transform: "translateY(-1px)",
|
||||
boxShadow: "sm",
|
||||
}}
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={onFolderModalClose}
|
||||
color="gray.300"
|
||||
_hover={{
|
||||
bg: "whiteAlpha.200",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user