Add sidebar image option

This commit is contained in:
jeffvli
2022-10-26 21:44:25 -07:00
parent 17258e950e
commit 88e716b970
4 changed files with 289 additions and 134 deletions
@@ -1,7 +1,10 @@
import styled from '@emotion/styled';
import { Text } from '../../../components';
import { usePlayerStore } from '../../../store';
import { Font } from '../../../styles';
import { Group } from '@mantine/core';
import { motion, AnimatePresence } from 'framer-motion';
import { RiArrowUpSLine } from 'react-icons/ri';
import { Button, Text } from '@/renderer/components';
import { useAppStore, usePlayerStore } from '@/renderer/store';
import { Font } from '@/renderer/styles';
const LeftControlsContainer = styled.div`
display: flex;
@@ -25,7 +28,25 @@ const MetadataStack = styled.div`
overflow: hidden;
`;
const Image = styled(motion.div)<{ url: string }>`
width: 70px;
height: 70px;
background-image: url(${(props) => props.url});
background-repeat: no-repeat;
background-size: cover;
button {
display: none;
}
&:hover button {
display: block;
}
`;
export const LeftControls = () => {
const hideImage = useAppStore((state) => state.sidebar.image);
const setSidebar = useAppStore((state) => state.setSidebar);
const song = usePlayerStore((state) => state.current.song);
const title = song?.name;
const artists = song?.artists?.map((artist) => artist?.name).join(', ');
@@ -34,9 +55,31 @@ export const LeftControls = () => {
return (
<LeftControlsContainer>
<ImageWrapper>
{song?.imageUrl && (
<img alt="img" height={60} src={song?.imageUrl} width={60} />
)}
<AnimatePresence>
{!hideImage && (
<Image
key="playerbar-image"
animate={{ opacity: 1, scale: 1, x: 0 }}
exit={{ opacity: 0, y: 50 }}
initial={{ opacity: 0, x: -50 }}
transition={{ duration: 0.3, ease: 'easeInOut' }}
url={song?.imageUrl}
>
<Group position="right">
<Button
compact
variant="subtle"
onClick={(e) => {
e.stopPropagation();
setSidebar({ image: true });
}}
>
<RiArrowUpSLine color="white" size={20} />
</Button>
</Group>
</Image>
)}
</AnimatePresence>
</ImageWrapper>
<MetadataStack>
<Text
@@ -1,8 +1,11 @@
import { useMemo } from 'react';
import styled from '@emotion/styled';
import { Stack, Group, Grid, Accordion } from '@mantine/core';
import { SpotlightProvider, openSpotlight } from '@mantine/spotlight';
import { AnimatePresence, motion } from 'framer-motion';
import {
RiAlbumLine,
RiArrowDownSLine,
RiArrowLeftSLine,
RiArrowRightSLine,
RiDatabaseLine,
@@ -16,120 +19,182 @@ import {
} from 'react-icons/ri';
import { useNavigate } from 'react-router';
import { Button, TextInput } from '@/renderer/components';
import { AppRoute } from '../../../router/routes';
import { AppRoute } from '@/renderer/router/routes';
import { useAppStore, usePlayerStore } from '@/renderer/store';
import { SidebarItem } from './sidebar-item';
const StyledSidebar = styled.div``;
const SidebarContainer = styled.div`
height: 100%;
max-height: calc(100vh - 120px); // Account for titlebar and playerbar
`;
const Image = styled(motion.div)<{ height: string; url: string }>`
height: ${(props) => props.height};
background-image: ${(props) => `url(${props.url})`};
background-repeat: no-repeat;
background-size: cover;
transition: background-image 0.5s linear 0.2s;
button {
display: none;
}
&:hover button {
display: block;
}
`;
export const Sidebar = () => {
const navigate = useNavigate();
const playerData = usePlayerStore((state) => state.getPlayerData());
const sidebar = useAppStore((state) => state.sidebar);
const setSidebar = useAppStore((state) => state.setSidebar);
const showImage = sidebar.image;
const backgroundImage = useMemo(() => {
return playerData.current.song.imageUrl;
}, [playerData]);
return (
<StyledSidebar>
<Stack p={10}>
<Grid>
<Grid.Col span={8}>
<SpotlightProvider actions={[]}>
<TextInput
readOnly
icon={<RiSearchLine />}
placeholder="Search"
rightSectionWidth={90}
onClick={() => openSpotlight()}
/>
</SpotlightProvider>
</Grid.Col>
<Grid.Col span={4}>
<Group grow spacing={5}>
<Button
px={5}
sx={{ color: 'var(--titlebar-fg)' }}
variant="default"
onClick={() => navigate(-1)}
>
<RiArrowLeftSLine size={20} />
</Button>
<Button
px={5}
sx={{ color: 'var(--titlebar-fg)' }}
variant="default"
onClick={() => navigate(1)}
>
<RiArrowRightSLine size={20} />
</Button>
</Group>
</Grid.Col>
</Grid>
<SidebarContainer>
<Stack justify="space-between" spacing={0} sx={{ height: '100%' }}>
<Stack
sx={{
maxHeight: showImage ? `calc(100% - ${sidebar.leftWidth})` : '100%',
}}
>
<Grid p={10}>
<Grid.Col span={8}>
<SpotlightProvider actions={[]}>
<TextInput
readOnly
icon={<RiSearchLine />}
placeholder="Search"
rightSectionWidth={90}
onClick={() => openSpotlight()}
/>
</SpotlightProvider>
</Grid.Col>
<Grid.Col span={4}>
<Group grow spacing={5}>
<Button
px={5}
sx={{ color: 'var(--titlebar-fg)' }}
variant="default"
onClick={() => navigate(-1)}
>
<RiArrowLeftSLine size={20} />
</Button>
<Button
px={5}
sx={{ color: 'var(--titlebar-fg)' }}
variant="default"
onClick={() => navigate(1)}
>
<RiArrowRightSLine size={20} />
</Button>
</Group>
</Grid.Col>
</Grid>
<Stack spacing={0} sx={{ overflowY: 'auto' }}>
<SidebarItem to={AppRoute.HOME}>
<Group>
<RiHome5Line size={15} />
Home
</Group>
</SidebarItem>
<SidebarItem>
<SidebarItem.Link disabled to={AppRoute.EXPLORE}>
<Group>
<RiEyeLine />
Explore
</Group>
</SidebarItem.Link>
</SidebarItem>
<Accordion disableChevronRotation multiple>
<Accordion.Item value="library">
<Accordion.Control p="1rem">
<Group>
<RiDatabaseLine size={15} />
Library
</Group>
</Accordion.Control>
<Accordion.Panel>
<SidebarItem to={AppRoute.LIBRARY_ALBUMS}>
<Group>
<RiAlbumLine />
Albums
</Group>
</SidebarItem>
<SidebarItem disabled to={AppRoute.LIBRARY_SONGS}>
<Group>
<RiMusicLine />
Tracks
</Group>
</SidebarItem>
<SidebarItem disabled to={AppRoute.LIBRARY_ALBUMARTISTS}>
<Group>
<RiUserVoiceLine />
Artists
</Group>
</SidebarItem>
<SidebarItem disabled to={AppRoute.LIBRARY_FOLDERS}>
<Group>
<RiFolder3Line />
Folders
</Group>
</SidebarItem>
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="collections">
<Accordion.Control disabled p="1rem">
<Group>
<RiPlayListLine size={20} />
Collections
</Group>
</Accordion.Control>
<Accordion.Panel />
</Accordion.Item>
<Accordion.Item value="playlists">
<Accordion.Control disabled p="1rem">
<Group>
<RiPlayListLine size={20} />
Playlists
</Group>
</Accordion.Control>
<Accordion.Panel />
</Accordion.Item>
</Accordion>
</Stack>
</Stack>
<AnimatePresence>
{showImage && (
<Image
key="sidebar-image"
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0 }}
height={sidebar.leftWidth}
initial={{ opacity: 0, y: 200 }}
transition={{ duration: 0.3, ease: 'easeInOut' }}
url={backgroundImage}
>
<Group position="right">
<Button
compact
variant="subtle"
onClick={(e) => {
e.stopPropagation();
setSidebar({ image: false });
}}
>
<RiArrowDownSLine color="white" size={20} />
</Button>
</Group>
</Image>
)}
</AnimatePresence>
</Stack>
<SidebarItem to={AppRoute.HOME}>
<Group>
<RiHome5Line size={15} />
Home
</Group>
</SidebarItem>
<SidebarItem>
<SidebarItem.Link disabled to={AppRoute.EXPLORE}>
<Group>
<RiEyeLine />
Explore
</Group>
</SidebarItem.Link>
</SidebarItem>
<Accordion disableChevronRotation multiple>
<Accordion.Item value="library">
<Accordion.Control p="1rem">
<Group>
<RiDatabaseLine size={15} />
Library
</Group>
</Accordion.Control>
<Accordion.Panel>
<SidebarItem to={AppRoute.LIBRARY_ALBUMS}>
<Group>
<RiAlbumLine />
Albums
</Group>
</SidebarItem>
<SidebarItem disabled to={AppRoute.LIBRARY_SONGS}>
<Group>
<RiMusicLine />
Tracks
</Group>
</SidebarItem>
<SidebarItem disabled to={AppRoute.LIBRARY_ALBUMARTISTS}>
<Group>
<RiUserVoiceLine />
Artists
</Group>
</SidebarItem>
<SidebarItem disabled to={AppRoute.LIBRARY_FOLDERS}>
<Group>
<RiFolder3Line />
Folders
</Group>
</SidebarItem>
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="collections">
<Accordion.Control disabled p="1rem">
<Group>
<RiPlayListLine size={20} />
Collections
</Group>
</Accordion.Control>
<Accordion.Panel />
</Accordion.Item>
<Accordion.Item value="playlists">
<Accordion.Control disabled p="1rem">
<Group>
<RiPlayListLine size={20} />
Playlists
</Group>
</Accordion.Control>
<Accordion.Panel />
</Accordion.Item>
</Accordion>
</StyledSidebar>
</SidebarContainer>
);
};