mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-09 20:29:36 +02:00
Add sidebar image option
This commit is contained in:
@@ -1,7 +1,10 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { Text } from '../../../components';
|
import { Group } from '@mantine/core';
|
||||||
import { usePlayerStore } from '../../../store';
|
import { motion, AnimatePresence } from 'framer-motion';
|
||||||
import { Font } from '../../../styles';
|
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`
|
const LeftControlsContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -25,7 +28,25 @@ const MetadataStack = styled.div`
|
|||||||
overflow: hidden;
|
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 = () => {
|
export const LeftControls = () => {
|
||||||
|
const hideImage = useAppStore((state) => state.sidebar.image);
|
||||||
|
const setSidebar = useAppStore((state) => state.setSidebar);
|
||||||
const song = usePlayerStore((state) => state.current.song);
|
const song = usePlayerStore((state) => state.current.song);
|
||||||
const title = song?.name;
|
const title = song?.name;
|
||||||
const artists = song?.artists?.map((artist) => artist?.name).join(', ');
|
const artists = song?.artists?.map((artist) => artist?.name).join(', ');
|
||||||
@@ -34,9 +55,31 @@ export const LeftControls = () => {
|
|||||||
return (
|
return (
|
||||||
<LeftControlsContainer>
|
<LeftControlsContainer>
|
||||||
<ImageWrapper>
|
<ImageWrapper>
|
||||||
{song?.imageUrl && (
|
<AnimatePresence>
|
||||||
<img alt="img" height={60} src={song?.imageUrl} width={60} />
|
{!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>
|
</ImageWrapper>
|
||||||
<MetadataStack>
|
<MetadataStack>
|
||||||
<Text
|
<Text
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { Stack, Group, Grid, Accordion } from '@mantine/core';
|
import { Stack, Group, Grid, Accordion } from '@mantine/core';
|
||||||
import { SpotlightProvider, openSpotlight } from '@mantine/spotlight';
|
import { SpotlightProvider, openSpotlight } from '@mantine/spotlight';
|
||||||
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
import {
|
import {
|
||||||
RiAlbumLine,
|
RiAlbumLine,
|
||||||
|
RiArrowDownSLine,
|
||||||
RiArrowLeftSLine,
|
RiArrowLeftSLine,
|
||||||
RiArrowRightSLine,
|
RiArrowRightSLine,
|
||||||
RiDatabaseLine,
|
RiDatabaseLine,
|
||||||
@@ -16,120 +19,182 @@ import {
|
|||||||
} from 'react-icons/ri';
|
} from 'react-icons/ri';
|
||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
import { Button, TextInput } from '@/renderer/components';
|
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';
|
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 = () => {
|
export const Sidebar = () => {
|
||||||
const navigate = useNavigate();
|
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 (
|
return (
|
||||||
<StyledSidebar>
|
<SidebarContainer>
|
||||||
<Stack p={10}>
|
<Stack justify="space-between" spacing={0} sx={{ height: '100%' }}>
|
||||||
<Grid>
|
<Stack
|
||||||
<Grid.Col span={8}>
|
sx={{
|
||||||
<SpotlightProvider actions={[]}>
|
maxHeight: showImage ? `calc(100% - ${sidebar.leftWidth})` : '100%',
|
||||||
<TextInput
|
}}
|
||||||
readOnly
|
>
|
||||||
icon={<RiSearchLine />}
|
<Grid p={10}>
|
||||||
placeholder="Search"
|
<Grid.Col span={8}>
|
||||||
rightSectionWidth={90}
|
<SpotlightProvider actions={[]}>
|
||||||
onClick={() => openSpotlight()}
|
<TextInput
|
||||||
/>
|
readOnly
|
||||||
</SpotlightProvider>
|
icon={<RiSearchLine />}
|
||||||
</Grid.Col>
|
placeholder="Search"
|
||||||
<Grid.Col span={4}>
|
rightSectionWidth={90}
|
||||||
<Group grow spacing={5}>
|
onClick={() => openSpotlight()}
|
||||||
<Button
|
/>
|
||||||
px={5}
|
</SpotlightProvider>
|
||||||
sx={{ color: 'var(--titlebar-fg)' }}
|
</Grid.Col>
|
||||||
variant="default"
|
<Grid.Col span={4}>
|
||||||
onClick={() => navigate(-1)}
|
<Group grow spacing={5}>
|
||||||
>
|
<Button
|
||||||
<RiArrowLeftSLine size={20} />
|
px={5}
|
||||||
</Button>
|
sx={{ color: 'var(--titlebar-fg)' }}
|
||||||
<Button
|
variant="default"
|
||||||
px={5}
|
onClick={() => navigate(-1)}
|
||||||
sx={{ color: 'var(--titlebar-fg)' }}
|
>
|
||||||
variant="default"
|
<RiArrowLeftSLine size={20} />
|
||||||
onClick={() => navigate(1)}
|
</Button>
|
||||||
>
|
<Button
|
||||||
<RiArrowRightSLine size={20} />
|
px={5}
|
||||||
</Button>
|
sx={{ color: 'var(--titlebar-fg)' }}
|
||||||
</Group>
|
variant="default"
|
||||||
</Grid.Col>
|
onClick={() => navigate(1)}
|
||||||
</Grid>
|
>
|
||||||
|
<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>
|
</Stack>
|
||||||
<SidebarItem to={AppRoute.HOME}>
|
</SidebarContainer>
|
||||||
<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>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,9 +2,13 @@ import { useCallback, useEffect, useRef, useState } from 'react';
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { Menu, Button } from '@mantine/core';
|
import { Menu, Button } from '@mantine/core';
|
||||||
import { Outlet } from 'react-router';
|
import { Outlet } from 'react-router';
|
||||||
|
import { SideQueue } from '@/renderer/features/side-queue/components/SideQueue';
|
||||||
import { Titlebar } from '@/renderer/features/titlebar/components/titlebar';
|
import { Titlebar } from '@/renderer/features/titlebar/components/titlebar';
|
||||||
import { useAppStore } from '@/renderer/store';
|
import { useAppStore } from '@/renderer/store';
|
||||||
import { constrainSidebarWidth } from '@/renderer/utils';
|
import {
|
||||||
|
constrainRightSidebarWidth,
|
||||||
|
constrainSidebarWidth,
|
||||||
|
} from '@/renderer/utils';
|
||||||
import { Playerbar } from '../features/player';
|
import { Playerbar } from '../features/player';
|
||||||
import { Sidebar } from '../features/sidebar/components/sidebar';
|
import { Sidebar } from '../features/sidebar/components/sidebar';
|
||||||
|
|
||||||
@@ -26,12 +30,17 @@ const TitlebarContainer = styled.header`
|
|||||||
-webkit-app-region: drag;
|
-webkit-app-region: drag;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const MainContainer = styled.main<{ leftSidebarWidth: string }>`
|
const MainContainer = styled.main<{
|
||||||
|
leftSidebarWidth: string;
|
||||||
|
rightExpanded?: boolean;
|
||||||
|
rightSidebarWidth?: string;
|
||||||
|
}>`
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-area: main;
|
grid-area: main;
|
||||||
grid-template-areas: 'sidebar .';
|
grid-template-areas: 'sidebar . right-sidebar';
|
||||||
grid-template-rows: 1fr;
|
grid-template-rows: 1fr;
|
||||||
grid-template-columns: ${(props) => props.leftSidebarWidth} 1fr;
|
grid-template-columns: ${(props) => props.leftSidebarWidth} 1fr ${(props) =>
|
||||||
|
props.rightExpanded && props.rightSidebarWidth};
|
||||||
gap: 0;
|
gap: 0;
|
||||||
background: var(--main-bg);
|
background: var(--main-bg);
|
||||||
`;
|
`;
|
||||||
@@ -42,7 +51,14 @@ const SidebarContainer = styled.div`
|
|||||||
background: var(--sidebar-bg);
|
background: var(--sidebar-bg);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const RightSidebarContainer = styled.div`
|
||||||
|
position: relative;
|
||||||
|
grid-area: right-sidebar;
|
||||||
|
background: var(--sidebar-bg);
|
||||||
|
`;
|
||||||
|
|
||||||
const PlayerbarContainer = styled.footer`
|
const PlayerbarContainer = styled.footer`
|
||||||
|
z-index: 50;
|
||||||
grid-area: player;
|
grid-area: player;
|
||||||
background: var(--playerbar-bg);
|
background: var(--playerbar-bg);
|
||||||
`;
|
`;
|
||||||
@@ -52,20 +68,16 @@ const ResizeHandle = styled.div<{
|
|||||||
placement: 'top' | 'left' | 'bottom' | 'right';
|
placement: 'top' | 'left' | 'bottom' | 'right';
|
||||||
}>`
|
}>`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
top: ${(props) => props.placement === 'top' && 0};
|
||||||
|
right: ${(props) => props.placement === 'right' && 0};
|
||||||
|
bottom: ${(props) => props.placement === 'bottom' && 0};
|
||||||
|
left: ${(props) => props.placement === 'left' && 0};
|
||||||
|
z-index: 100;
|
||||||
width: 3px;
|
width: 3px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
right: 0;
|
|
||||||
background-color: var(--sidebar-handle-bg);
|
background-color: var(--sidebar-handle-bg);
|
||||||
/* border-top: ${({ placement }) =>
|
|
||||||
placement === 'top' && '1px var(--sidebar-handle-bg) solid'};
|
|
||||||
border-right: ${({ placement }) =>
|
|
||||||
placement === 'right' && '1px var(--sidebar-handle-bg) solid'};
|
|
||||||
border-bottom: ${({ placement }) =>
|
|
||||||
placement === 'bottom' && '1px var(--sidebar-handle-bg) solid'};
|
|
||||||
border-left: ${({ placement }) =>
|
|
||||||
placement === 'left' && '1px var(--sidebar-handle-bg) solid'}; */
|
|
||||||
opacity: ${(props) => (props.isResizing ? 1 : 0)};
|
|
||||||
cursor: ew-resize;
|
cursor: ew-resize;
|
||||||
|
opacity: ${(props) => (props.isResizing ? 1 : 0)};
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
@@ -76,15 +88,19 @@ export const DefaultLayout = () => {
|
|||||||
const sidebar = useAppStore((state) => state.sidebar);
|
const sidebar = useAppStore((state) => state.sidebar);
|
||||||
const setSidebar = useAppStore((state) => state.setSidebar);
|
const setSidebar = useAppStore((state) => state.setSidebar);
|
||||||
|
|
||||||
const sidebarRef = useRef(null);
|
const sidebarRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
const rightSidebarRef = useRef<HTMLDivElement | null>(null);
|
||||||
const [isResizing, setIsResizing] = useState(false);
|
const [isResizing, setIsResizing] = useState(false);
|
||||||
|
const [isResizingRight, setIsResizingRight] = useState(false);
|
||||||
|
|
||||||
const startResizing = useCallback(() => {
|
const startResizing = useCallback((position: 'left' | 'right') => {
|
||||||
setIsResizing(true);
|
if (position === 'left') return setIsResizing(true);
|
||||||
|
return setIsResizingRight(true);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const stopResizing = useCallback(() => {
|
const stopResizing = useCallback(() => {
|
||||||
setIsResizing(false);
|
setIsResizing(false);
|
||||||
|
setIsResizingRight(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const resize = useCallback(
|
const resize = useCallback(
|
||||||
@@ -93,8 +109,16 @@ export const DefaultLayout = () => {
|
|||||||
const width = `${constrainSidebarWidth(mouseMoveEvent.clientX)}px`;
|
const width = `${constrainSidebarWidth(mouseMoveEvent.clientX)}px`;
|
||||||
setSidebar({ leftWidth: width });
|
setSidebar({ leftWidth: width });
|
||||||
}
|
}
|
||||||
|
if (isResizingRight) {
|
||||||
|
const start = Number(sidebar.rightWidth.split('px')[0]);
|
||||||
|
const { left } = rightSidebarRef!.current!.getBoundingClientRect();
|
||||||
|
const width = `${constrainRightSidebarWidth(
|
||||||
|
start + left - mouseMoveEvent.clientX
|
||||||
|
)}px`;
|
||||||
|
setSidebar({ rightWidth: width });
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[isResizing, setSidebar]
|
[isResizing, isResizingRight, setSidebar, sidebar.rightWidth]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -121,19 +145,35 @@ export const DefaultLayout = () => {
|
|||||||
</Menu.Dropdown>
|
</Menu.Dropdown>
|
||||||
</Menu>
|
</Menu>
|
||||||
</TitlebarContainer>
|
</TitlebarContainer>
|
||||||
<MainContainer leftSidebarWidth={sidebar.leftWidth}>
|
<MainContainer
|
||||||
|
leftSidebarWidth={sidebar.leftWidth}
|
||||||
|
rightExpanded={sidebar.rightExpanded}
|
||||||
|
rightSidebarWidth={sidebar.rightWidth}
|
||||||
|
>
|
||||||
<SidebarContainer>
|
<SidebarContainer>
|
||||||
<ResizeHandle
|
<ResizeHandle
|
||||||
ref={sidebarRef}
|
ref={sidebarRef}
|
||||||
isResizing={isResizing}
|
isResizing={isResizing}
|
||||||
placement="left"
|
placement="right"
|
||||||
onMouseDown={(e) => {
|
onMouseDown={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
startResizing();
|
startResizing('left');
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
</SidebarContainer>
|
</SidebarContainer>
|
||||||
|
<RightSidebarContainer>
|
||||||
|
<ResizeHandle
|
||||||
|
ref={rightSidebarRef}
|
||||||
|
isResizing={isResizingRight}
|
||||||
|
placement="left"
|
||||||
|
onMouseDown={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
startResizing('right');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{sidebar.rightExpanded && <SideQueue />}
|
||||||
|
</RightSidebarContainer>
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</MainContainer>
|
</MainContainer>
|
||||||
<PlayerbarContainer>
|
<PlayerbarContainer>
|
||||||
|
|||||||
@@ -5,14 +5,19 @@ import { Platform } from '@/renderer/types';
|
|||||||
|
|
||||||
type SidebarProps = {
|
type SidebarProps = {
|
||||||
expanded: string[];
|
expanded: string[];
|
||||||
|
image: boolean;
|
||||||
leftWidth: string;
|
leftWidth: string;
|
||||||
|
rightExpanded: boolean;
|
||||||
rightWidth: string;
|
rightWidth: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface AppState {
|
export interface AppState {
|
||||||
platform: Platform;
|
platform: Platform;
|
||||||
sidebar: {
|
sidebar: {
|
||||||
expanded: string[];
|
expanded: string[];
|
||||||
|
image: boolean;
|
||||||
leftWidth: string;
|
leftWidth: string;
|
||||||
|
rightExpanded: boolean;
|
||||||
rightWidth: string;
|
rightWidth: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -37,7 +42,9 @@ export const useAppStore = create<AppSlice>()(
|
|||||||
},
|
},
|
||||||
sidebar: {
|
sidebar: {
|
||||||
expanded: [],
|
expanded: [],
|
||||||
|
image: false,
|
||||||
leftWidth: '230px',
|
leftWidth: '230px',
|
||||||
|
rightExpanded: false,
|
||||||
rightWidth: '230px',
|
rightWidth: '230px',
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
|
|||||||
Reference in New Issue
Block a user