Draggable playlist sidebar
This commit is contained in:
parent
83fe6994b8
commit
f82cb84397
@ -1,5 +1,5 @@
|
|||||||
import { Box, Button, Flex, Heading, Input, Spinner, Text, useStyleConfig, useBreakpointValue, IconButton, Drawer, DrawerBody, DrawerHeader, DrawerOverlay, DrawerContent, DrawerCloseButton, useDisclosure, Container, Menu, MenuButton, MenuList, MenuItem } from "@chakra-ui/react";
|
import { Box, Button, Flex, Heading, Input, Spinner, Text, useStyleConfig, useBreakpointValue, IconButton, Drawer, DrawerBody, DrawerHeader, DrawerOverlay, DrawerContent, DrawerCloseButton, useDisclosure, Container, Menu, MenuButton, MenuList, MenuItem, useToken } from "@chakra-ui/react";
|
||||||
import { ChevronLeftIcon, ChevronRightIcon, HamburgerIcon, ViewIcon, SettingsIcon } from "@chakra-ui/icons";
|
import { ChevronLeftIcon, ChevronRightIcon, HamburgerIcon, ViewIcon, SettingsIcon, DragHandleIcon } from "@chakra-ui/icons";
|
||||||
import { useState, useRef, useEffect } from "react";
|
import { useState, useRef, useEffect } from "react";
|
||||||
import { useNavigate, useLocation } from "react-router-dom";
|
import { useNavigate, useLocation } from "react-router-dom";
|
||||||
import { SongList } from "./components/SongList";
|
import { SongList } from "./components/SongList";
|
||||||
@ -63,6 +63,35 @@ const StyledFileInput = ({ isMobile = false }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ResizeHandle = ({ onMouseDown }: { onMouseDown: (e: React.MouseEvent) => void }) => (
|
||||||
|
<Box
|
||||||
|
position="absolute"
|
||||||
|
right="-4px"
|
||||||
|
top={0}
|
||||||
|
bottom={0}
|
||||||
|
width="8px"
|
||||||
|
cursor="col-resize"
|
||||||
|
zIndex={1}
|
||||||
|
_hover={{
|
||||||
|
'&::after': {
|
||||||
|
bg: 'blue.500',
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onMouseDown={onMouseDown}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
position="absolute"
|
||||||
|
left="3px"
|
||||||
|
top={0}
|
||||||
|
bottom={0}
|
||||||
|
width="2px"
|
||||||
|
bg="gray.600"
|
||||||
|
transition="background-color 0.2s"
|
||||||
|
_hover={{ bg: 'blue.500' }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
|
||||||
export default function RekordboxReader() {
|
export default function RekordboxReader() {
|
||||||
const { songs, playlists, setPlaylists, loading } = useXmlParser();
|
const { songs, playlists, setPlaylists, loading } = useXmlParser();
|
||||||
const [selectedSong, setSelectedSong] = useState<Song | null>(null);
|
const [selectedSong, setSelectedSong] = useState<Song | null>(null);
|
||||||
@ -73,6 +102,9 @@ export default function RekordboxReader() {
|
|||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
|
|
||||||
const isMobile = useBreakpointValue({ base: true, md: false });
|
const isMobile = useBreakpointValue({ base: true, md: false });
|
||||||
|
const [sidebarWidth, setSidebarWidth] = useState(400);
|
||||||
|
const [isResizing, setIsResizing] = useState(false);
|
||||||
|
const resizeRef = useRef<{ startX: number; startWidth: number } | null>(null);
|
||||||
|
|
||||||
// Get the current playlist from URL or default to "All Songs"
|
// Get the current playlist from URL or default to "All Songs"
|
||||||
const currentPlaylist = location.pathname === "/"
|
const currentPlaylist = location.pathname === "/"
|
||||||
@ -161,6 +193,39 @@ export default function RekordboxReader() {
|
|||||||
playlists.find((p) => p.name === currentPlaylist)?.tracks.includes(song.id)
|
playlists.find((p) => p.name === currentPlaylist)?.tracks.includes(song.id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleResizeStart = (e: React.MouseEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setIsResizing(true);
|
||||||
|
resizeRef.current = {
|
||||||
|
startX: e.pageX,
|
||||||
|
startWidth: sidebarWidth,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleResizeMove = (e: MouseEvent) => {
|
||||||
|
if (!isResizing || !resizeRef.current) return;
|
||||||
|
|
||||||
|
const delta = e.pageX - resizeRef.current.startX;
|
||||||
|
const newWidth = Math.max(300, Math.min(800, resizeRef.current.startWidth + delta));
|
||||||
|
setSidebarWidth(newWidth);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleResizeEnd = () => {
|
||||||
|
setIsResizing(false);
|
||||||
|
resizeRef.current = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isResizing) {
|
||||||
|
window.addEventListener('mousemove', handleResizeMove);
|
||||||
|
window.addEventListener('mouseup', handleResizeEnd);
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('mousemove', handleResizeMove);
|
||||||
|
window.removeEventListener('mouseup', handleResizeEnd);
|
||||||
|
};
|
||||||
|
}, [isResizing]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<Flex height="100vh" align="center" justify="center" direction="column" gap={4}>
|
<Flex height="100vh" align="center" justify="center" direction="column" gap={4}>
|
||||||
@ -198,6 +263,7 @@ export default function RekordboxReader() {
|
|||||||
overflow="hidden"
|
overflow="hidden"
|
||||||
margin={0}
|
margin={0}
|
||||||
padding={0}
|
padding={0}
|
||||||
|
userSelect={isResizing ? 'none' : 'auto'}
|
||||||
>
|
>
|
||||||
<Flex direction="column" h="100%" w="100%">
|
<Flex direction="column" h="100%" w="100%">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
@ -275,8 +341,9 @@ export default function RekordboxReader() {
|
|||||||
{/* Sidebar - Desktop */}
|
{/* Sidebar - Desktop */}
|
||||||
{!isMobile && (
|
{!isMobile && (
|
||||||
<Box
|
<Box
|
||||||
w="300px"
|
position="relative"
|
||||||
minW="300px"
|
w={`${sidebarWidth}px`}
|
||||||
|
minW={`${sidebarWidth}px`}
|
||||||
p={4}
|
p={4}
|
||||||
borderRight="1px"
|
borderRight="1px"
|
||||||
borderColor="gray.700"
|
borderColor="gray.700"
|
||||||
@ -284,6 +351,7 @@ export default function RekordboxReader() {
|
|||||||
bg="gray.900"
|
bg="gray.900"
|
||||||
>
|
>
|
||||||
{playlistManager}
|
{playlistManager}
|
||||||
|
<ResizeHandle onMouseDown={handleResizeStart} />
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user