From c8a0df4759ff5a6add30d339c068763834842b32 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Sat, 3 Jun 2023 05:36:38 -0700 Subject: [PATCH] Add configurable sidebar --- .../sidebar/components/collapsed-sidebar.tsx | 146 ++++++------ .../sidebar/components/sidebar-item.tsx | 2 +- .../features/sidebar/components/sidebar.tsx | 223 +++++++++--------- src/renderer/store/settings.store.ts | 22 +- src/renderer/themes/default.scss | 2 +- 5 files changed, 207 insertions(+), 188 deletions(-) diff --git a/src/renderer/features/sidebar/components/collapsed-sidebar.tsx b/src/renderer/features/sidebar/components/collapsed-sidebar.tsx index 2c95dcbf..1c7dd4f3 100644 --- a/src/renderer/features/sidebar/components/collapsed-sidebar.tsx +++ b/src/renderer/features/sidebar/components/collapsed-sidebar.tsx @@ -1,9 +1,10 @@ import { UnstyledButton } from '@mantine/core'; import { motion } from 'framer-motion'; +import { useMemo } from 'react'; +import { IconType } from 'react-icons'; import { RiUserVoiceLine, RiMenuFill, - RiFlag2Line, RiFolder3Line, RiPlayListLine, RiAlbumLine, @@ -18,14 +19,20 @@ import { RiPlayListFill, RiSearchLine, RiSearchFill, + RiPlayFill, + RiPlayLine, + RiSettings2Fill, + RiSettings2Line, + RiFlag2Line, } from 'react-icons/ri'; -import { NavLink } from 'react-router-dom'; +import { generatePath, NavLink } from 'react-router-dom'; import styled from 'styled-components'; +import { LibraryItem } from '/@/renderer/api/types'; import { DropdownMenu, ScrollArea } from '/@/renderer/components'; import { CollapsedSidebarItem } from '/@/renderer/features/sidebar/components/collapsed-sidebar-item'; import { AppMenu } from '/@/renderer/features/titlebar/components/app-menu'; import { AppRoute } from '/@/renderer/router/routes'; -import { useCommandPalette, useWindowSettings } from '/@/renderer/store'; +import { SidebarItemType, useGeneralSettings, useWindowSettings } from '/@/renderer/store'; import { Platform } from '/@/renderer/types'; const SidebarContainer = styled(motion.div)<{ windowBarStyle: Platform }>` @@ -39,9 +46,68 @@ const SidebarContainer = styled(motion.div)<{ windowBarStyle: Platform }>` user-select: none; `; +const sidebarItemMap = { + [AppRoute.HOME]: { + activeIcon: RiHome6Fill, + icon: RiHome6Line, + }, + [AppRoute.LIBRARY_ALBUMS]: { + activeIcon: RiAlbumFill, + icon: RiAlbumLine, + }, + [AppRoute.LIBRARY_ALBUM_ARTISTS]: { + activeIcon: RiUserVoiceFill, + icon: RiUserVoiceLine, + }, + [AppRoute.PLAYLISTS]: { + activeIcon: RiPlayListFill, + icon: RiPlayListLine, + }, + [AppRoute.LIBRARY_SONGS]: { + activeIcon: RiMusic2Fill, + icon: RiMusic2Line, + }, + [AppRoute.LIBRARY_FOLDERS]: { + activeIcon: RiFolder3Fill, + icon: RiFolder3Line, + }, + [AppRoute.LIBRARY_GENRES]: { + activeIcon: RiFlag2Fill, + icon: RiFlag2Line, + }, + [generatePath(AppRoute.SEARCH, { itemType: LibraryItem.SONG })]: { + activeIcon: RiSearchFill, + icon: RiSearchLine, + }, + [AppRoute.SETTINGS]: { + activeIcon: RiSettings2Fill, + icon: RiSettings2Line, + }, + [AppRoute.NOW_PLAYING]: { + activeIcon: RiPlayFill, + icon: RiPlayLine, + }, +}; + export const CollapsedSidebar = () => { const { windowBarStyle } = useWindowSettings(); - const { open } = useCommandPalette(); + const { sidebarItems } = useGeneralSettings(); + + const sidebarItemsWithRoute: (SidebarItemType & { + activeIcon: IconType; + icon: IconType; + })[] = useMemo(() => { + if (!sidebarItems) return []; + + const items = sidebarItems + .filter((item) => !item.disabled) + .map((item) => ({ + ...item, + ...sidebarItemMap[item.route as keyof typeof sidebarItemMap], + })); + + return items; + }, [sidebarItems]); return ( @@ -62,68 +128,16 @@ export const CollapsedSidebar = () => { - } - icon={} - label="Search" - onClick={open} - /> - } - component={NavLink} - icon={} - label="Home" - route={AppRoute.HOME} - to={AppRoute.HOME} - /> - } - component={NavLink} - icon={} - label="Albums" - route={AppRoute.LIBRARY_ALBUMS} - to={AppRoute.LIBRARY_ALBUMS} - /> - } - component={NavLink} - icon={} - label="Tracks" - route={AppRoute.LIBRARY_SONGS} - to={AppRoute.LIBRARY_SONGS} - /> - } - component={NavLink} - icon={} - label="Artists" - route={AppRoute.LIBRARY_ALBUM_ARTISTS} - to={AppRoute.LIBRARY_ALBUM_ARTISTS} - /> - } - component={NavLink} - icon={} - label="Genres" - to={AppRoute.LIBRARY_GENRES} - /> - } - component={NavLink} - icon={} - label="Folders" - to={AppRoute.LIBRARY_FOLDERS} - /> - } - component={NavLink} - icon={} - label="Playlists" - route={AppRoute.PLAYLISTS} - to={AppRoute.PLAYLISTS} - /> + {sidebarItemsWithRoute.map((item) => ( + } + component={NavLink} + icon={} + label={item.label} + route={item.route} + to={item.route} + /> + ))} ); diff --git a/src/renderer/features/sidebar/components/sidebar-item.tsx b/src/renderer/features/sidebar/components/sidebar-item.tsx index 41816b23..bfbccad6 100644 --- a/src/renderer/features/sidebar/components/sidebar-item.tsx +++ b/src/renderer/features/sidebar/components/sidebar-item.tsx @@ -12,7 +12,7 @@ interface ListItemProps extends FlexProps { const StyledItem = styled(Flex)` width: 100%; - font-weight: 600; + font-weight: 700; font-family: var(--content-font-family); &:focus-visible { diff --git a/src/renderer/features/sidebar/components/sidebar.tsx b/src/renderer/features/sidebar/components/sidebar.tsx index a5743b3e..5310dd37 100644 --- a/src/renderer/features/sidebar/components/sidebar.tsx +++ b/src/renderer/features/sidebar/components/sidebar.tsx @@ -1,46 +1,59 @@ -import { MouseEvent } from 'react'; -import { Stack, Accordion, Center, Group, Divider, Box } from '@mantine/core'; +import { MouseEvent, useMemo } from 'react'; +import { Box, Center, Divider, Group, Stack } from '@mantine/core'; import { closeAllModals, openModal } from '@mantine/modals'; import { AnimatePresence, motion } from 'framer-motion'; -import { Button, MotionStack, Spinner, Tooltip } from '/@/renderer/components'; +import { IconType } from 'react-icons'; import { RiAddFill, RiAlbumFill, RiAlbumLine, RiArrowDownSLine, - RiDatabaseFill, - RiDatabaseLine, RiDiscLine, - RiFlag2Line, + RiFlag2Fill, + RiFlagLine, + RiFolder3Fill, RiFolder3Line, RiHome6Fill, RiHome6Line, RiListUnordered, RiMusic2Fill, RiMusic2Line, + RiPlayLine, + RiSearchFill, RiUserVoiceFill, RiUserVoiceLine, + RiSearchLine, + RiPlayFill, + RiSettings2Line, + RiSettings2Fill, + RiPlayListLine, + RiPlayListFill, } from 'react-icons/ri'; -import { Link, useLocation } from 'react-router-dom'; +import { generatePath, Link, useLocation } from 'react-router-dom'; import styled from 'styled-components'; -import { SidebarItem } from '/@/renderer/features/sidebar/components/sidebar-item'; -import { AppRoute } from '/@/renderer/router/routes'; import { - useSidebarStore, - useAppStoreActions, - useCurrentSong, - useCurrentServer, - useSetFullScreenPlayerStore, - useFullScreenPlayerStore, -} from '/@/renderer/store'; -import { fadeIn } from '/@/renderer/styles'; + SidebarItemType, + useGeneralSettings, + useWindowSettings, +} from '../../../store/settings.store'; +import { LibraryItem, PlaylistListSort, ServerType, SortOrder } from '/@/renderer/api/types'; +import { Button, MotionStack, Spinner, Tooltip } from '/@/renderer/components'; import { CreatePlaylistForm, usePlaylistList } from '/@/renderer/features/playlists'; -import { PlaylistListSort, ServerType, SortOrder } from '/@/renderer/api/types'; +import { ActionBar } from '/@/renderer/features/sidebar/components/action-bar'; +import { SidebarItem } from '/@/renderer/features/sidebar/components/sidebar-item'; import { SidebarPlaylistList } from '/@/renderer/features/sidebar/components/sidebar-playlist-list'; import { useContainerQuery } from '/@/renderer/hooks'; -import { ActionBar } from '/@/renderer/features/sidebar/components/action-bar'; +import { AppRoute } from '/@/renderer/router/routes'; +import { + useAppStoreActions, + useCurrentServer, + useCurrentSong, + useFullScreenPlayerStore, + useSetFullScreenPlayerStore, + useSidebarStore, +} from '/@/renderer/store'; +import { fadeIn } from '/@/renderer/styles'; import { Platform } from '/@/renderer/types'; -import { useWindowSettings } from '../../../store/settings.store'; const SidebarContainer = styled.div<{ windowBarStyle: Platform }>` height: 100%; @@ -75,6 +88,49 @@ const SidebarImage = styled.img` background: var(--placeholder-bg); `; +const sidebarItemMap = { + [AppRoute.HOME]: { + activeIcon: RiHome6Fill, + icon: RiHome6Line, + }, + [AppRoute.LIBRARY_ALBUMS]: { + activeIcon: RiAlbumFill, + icon: RiAlbumLine, + }, + [AppRoute.LIBRARY_ALBUM_ARTISTS]: { + activeIcon: RiUserVoiceFill, + icon: RiUserVoiceLine, + }, + [AppRoute.PLAYLISTS]: { + activeIcon: RiPlayListFill, + icon: RiPlayListLine, + }, + [AppRoute.LIBRARY_SONGS]: { + activeIcon: RiMusic2Fill, + icon: RiMusic2Line, + }, + [AppRoute.LIBRARY_FOLDERS]: { + activeIcon: RiFolder3Fill, + icon: RiFolder3Line, + }, + [AppRoute.LIBRARY_GENRES]: { + activeIcon: RiFlag2Fill, + icon: RiFlagLine, + }, + [generatePath(AppRoute.SEARCH, { itemType: LibraryItem.SONG })]: { + activeIcon: RiSearchFill, + icon: RiSearchLine, + }, + [AppRoute.SETTINGS]: { + activeIcon: RiSettings2Fill, + icon: RiSettings2Line, + }, + [AppRoute.NOW_PLAYING]: { + activeIcon: RiPlayFill, + icon: RiPlayLine, + }, +}; + export const Sidebar = () => { const location = useLocation(); const sidebar = useSidebarStore(); @@ -117,6 +173,24 @@ export const Sidebar = () => { const cq = useContainerQuery({ sm: 300 }); + const { sidebarItems } = useGeneralSettings(); + + const sidebarItemsWithRoute: (SidebarItemType & { + activeIcon: IconType; + icon: IconType; + })[] = useMemo(() => { + if (!sidebarItems) return []; + + const items = sidebarItems + .filter((item) => !item.disabled) + .map((item) => ({ + ...item, + ...sidebarItemMap[item.route as keyof typeof sidebarItemMap], + })); + + return items; + }, [sidebarItems]); + return ( { sx={{ maxHeight: showImage ? `calc(100% - ${sidebar.leftWidth})` : '100%' }} > - - - {location.pathname === AppRoute.HOME ? ( - - ) : ( - - )} - Home - - - setSideBar({ expanded: e })} - > - - - - {location.pathname.includes('/library/') ? ( - - ) : ( - - )} - Library - - - - - - {location.pathname === AppRoute.LIBRARY_ALBUMS ? ( - - ) : ( - - )} - Albums - - - - - {location.pathname === AppRoute.LIBRARY_SONGS ? ( - - ) : ( - - )} - Tracks - - - - - {location.pathname === AppRoute.LIBRARY_ALBUM_ARTISTS ? ( - - ) : ( - - )} - Album Artists - - - - - - Genres - - - - - - Folders - - - - - + {sidebarItemsWithRoute.map((item) => ( + + + {location.pathname === item.route ? ( + + ) : ( + + )} + {item.label} + + + ))} ()( return merge(currentState, persistedState); }, name: 'store_settings', - version: 5, + version: 6, }, ), ); diff --git a/src/renderer/themes/default.scss b/src/renderer/themes/default.scss index dbde2353..84981367 100644 --- a/src/renderer/themes/default.scss +++ b/src/renderer/themes/default.scss @@ -22,7 +22,7 @@ --sidebar-bg: rgb(0, 0, 0); --sidebar-bg-hover: rgb(50, 50, 50); - --sidebar-fg: rgb(210, 210, 210); + --sidebar-fg: rgb(190, 190, 190); --sidebar-fg-hover: rgb(255, 255, 255); --sidebar-handle-bg: #4d4d4d; --sidebar-border: 2px rgba(18, 18, 18, 0.7) solid;