From 83fe6994b8391f675d93f3a4e09f0a5387b400ea Mon Sep 17 00:00:00 2001 From: Geert Rademakes Date: Thu, 24 Apr 2025 23:11:07 +0200 Subject: [PATCH] Better UI! --- packages/frontend/src/App.css | 16 +- packages/frontend/src/App.tsx | 237 +++++++++++++++--- .../frontend/src/components/SongDetails.tsx | 135 ++++------ 3 files changed, 265 insertions(+), 123 deletions(-) diff --git a/packages/frontend/src/App.css b/packages/frontend/src/App.css index 3a094f1..2abd334 100644 --- a/packages/frontend/src/App.css +++ b/packages/frontend/src/App.css @@ -1,7 +1,19 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html, body, #root { + width: 100%; + height: 100%; + margin: 0; + padding: 0; + overflow: hidden; +} + #root { max-width: 1280px; - margin: 0; - padding: 1rem; } .logo { diff --git a/packages/frontend/src/App.tsx b/packages/frontend/src/App.tsx index de72e21..a05aab9 100644 --- a/packages/frontend/src/App.tsx +++ b/packages/frontend/src/App.tsx @@ -1,4 +1,5 @@ -import { Box, Button, Flex, Heading, Input, Spinner, Text, useStyleConfig } 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 } from "@chakra-ui/react"; +import { ChevronLeftIcon, ChevronRightIcon, HamburgerIcon, ViewIcon, SettingsIcon } from "@chakra-ui/icons"; import { useState, useRef, useEffect } from "react"; import { useNavigate, useLocation } from "react-router-dom"; import { SongList } from "./components/SongList"; @@ -10,7 +11,7 @@ import { api } from "./services/api"; import { Song } from "./types/interfaces"; import "./App.css"; -const StyledFileInput = () => { +const StyledFileInput = ({ isMobile = false }) => { const { handleFileUpload } = useXmlParser(); const inputRef = useRef(null); @@ -22,7 +23,7 @@ const StyledFileInput = () => { { bg: "gray.500" }} onClick={handleClick} + size={isMobile ? "sm" : "md"} > Choose XML File @@ -67,6 +69,10 @@ export default function RekordboxReader() { const navigate = useNavigate(); const location = useLocation(); const initialLoadDone = useRef(false); + const mobileFileInputRef = useRef(null); + const { isOpen, onOpen, onClose } = useDisclosure(); + + const isMobile = useBreakpointValue({ base: true, md: false }); // Get the current playlist from URL or default to "All Songs" const currentPlaylist = location.pathname === "/" @@ -169,41 +175,202 @@ export default function RekordboxReader() { ); } + const playlistManager = ( + { + handlePlaylistSelect(name || "All Songs"); + if (isMobile) onClose(); + }} + onPlaylistDelete={handlePlaylistDelete} + /> + ); + return ( - - - Rekordbox Reader - - - {songs.length > 0 && ( - + + + {/* Header */} + + {isMobile && ( + } + onClick={onOpen} + variant="solid" + colorScheme="blue" + size="md" + fontSize="20px" + /> + )} + Rekordbox Reader + + {/* Desktop Actions */} + {!isMobile && ( + + + {songs.length > 0 && ( + + )} + + )} + + {/* Mobile Actions */} + {isMobile && ( + + } + variant="ghost" + ml="auto" + size="md" + color="gray.300" + _hover={{ color: "white", bg: "whiteAlpha.200" }} + /> + + + + + {songs.length > 0 && ( + + Export XML + + )} + + )} - - - - - - - - - + + {/* Main Content */} + + {/* Sidebar - Desktop */} + {!isMobile && ( + + {playlistManager} + + )} + + {/* Sidebar - Mobile */} + + + + + Playlists + } + onClick={onClose} + variant="ghost" + ml="auto" + color="blue.400" + _hover={{ color: "blue.300", bg: "whiteAlpha.200" }} + /> + + + {playlistManager} + + + + + {/* Main Content Area */} + + {/* Song List */} + + + + + {/* Details Panel */} + {!isMobile && ( + + + + )} + + ); diff --git a/packages/frontend/src/components/SongDetails.tsx b/packages/frontend/src/components/SongDetails.tsx index 6b0594f..a9fddbb 100644 --- a/packages/frontend/src/components/SongDetails.tsx +++ b/packages/frontend/src/components/SongDetails.tsx @@ -8,17 +8,7 @@ interface SongDetailsProps { export const SongDetails: React.FC = ({ song }) => { if (!song) { return ( - + Select a song to view details ); @@ -36,84 +26,57 @@ export const SongDetails: React.FC = ({ song }) => { { label: "Mix", value: song.mix }, { label: "Rating", value: song.rating }, { label: "Comments", value: song.comments }, - ].filter(detail => detail.value); // Only show fields that have values + ].filter(detail => detail.value); return ( - - - - - - {song.title} - - - {song.artist} - - - - - {details.map(({ label, value }) => ( - - - {label} - - - {value} - - - ))} - - {song.tempo && ( - <> - - - - Tempo Details - - - - BPM - {song.tempo.bpm} - - - Beat - {song.tempo.battito} - - - Time Signature - {song.tempo.metro} - - - - - )} + + + + + {song.title} + + + {song.artist} + + + + + {details.map(({ label, value }) => ( + + + {label} + + + {value} + + + ))} - + {song.tempo && ( + <> + + + + Tempo Details + + + + BPM + {song.tempo.bpm} + + + Beat + {song.tempo.battito} + + + Time Signature + {song.tempo.metro} + + + + + )} + ); }; \ No newline at end of file