Lint all files

This commit is contained in:
jeffvli 2023-07-01 19:10:05 -07:00
parent 22af76b4d6
commit 30e52ebb54
334 changed files with 76519 additions and 75932 deletions

View file

@ -3,29 +3,29 @@ import styled from 'styled-components';
import { Titlebar } from '/@/renderer/features/titlebar/components/titlebar';
const WindowsTitlebarContainer = styled.div`
position: absolute;
z-index: 1000;
display: flex;
width: 100%;
height: 50px;
user-select: none;
-webkit-app-region: drag;
position: absolute;
z-index: 1000;
display: flex;
width: 100%;
height: 50px;
user-select: none;
-webkit-app-region: drag;
`;
const ContentContainer = styled.div`
display: flex;
height: 100%;
display: flex;
height: 100%;
`;
export const AuthLayout = () => {
return (
<>
<WindowsTitlebarContainer>
<Titlebar />
</WindowsTitlebarContainer>
<ContentContainer>
<Outlet />
</ContentContainer>
</>
);
return (
<>
<WindowsTitlebarContainer>
<Titlebar />
</WindowsTitlebarContainer>
<ContentContainer>
<Outlet />
</ContentContainer>
</>
);
};

View file

@ -2,11 +2,11 @@ import { lazy } from 'react';
import isElectron from 'is-electron';
import styled from 'styled-components';
import {
useWindowSettings,
useSettingsStore,
useHotkeySettings,
useGeneralSettings,
useSettingsStoreActions,
useWindowSettings,
useSettingsStore,
useHotkeySettings,
useGeneralSettings,
useSettingsStoreActions,
} from '/@/renderer/store/settings.store';
import { Platform, PlaybackType } from '/@/renderer/types';
import { MainContent } from '/@/renderer/layouts/default-layout/main-content';
@ -16,86 +16,86 @@ import { CommandPalette } from '/@/renderer/features/search/components/command-p
import { useCommandPalette } from '/@/renderer/store';
if (!isElectron()) {
useSettingsStore.getState().actions.setSettings({
playback: {
...useSettingsStore.getState().playback,
type: PlaybackType.WEB,
},
});
useSettingsStore.getState().actions.setSettings({
playback: {
...useSettingsStore.getState().playback,
type: PlaybackType.WEB,
},
});
}
const Layout = styled.div<{ windowBarStyle: Platform }>`
display: grid;
grid-template-areas:
'window-bar'
'main-content'
'player';
grid-template-rows: ${(props) =>
props.windowBarStyle === Platform.WINDOWS || props.windowBarStyle === Platform.MACOS
? '30px calc(100vh - 120px) 90px'
: '0px calc(100vh - 90px) 90px'};
grid-template-columns: 1fr;
gap: 0;
height: 100%;
overflow: hidden;
display: grid;
grid-template-areas:
'window-bar'
'main-content'
'player';
grid-template-rows: ${(props) =>
props.windowBarStyle === Platform.WINDOWS || props.windowBarStyle === Platform.MACOS
? '30px calc(100vh - 120px) 90px'
: '0px calc(100vh - 90px) 90px'};
grid-template-columns: 1fr;
gap: 0;
height: 100%;
overflow: hidden;
`;
const WindowBar = lazy(() =>
import('/@/renderer/layouts/window-bar').then((module) => ({
default: module.WindowBar,
})),
import('/@/renderer/layouts/window-bar').then((module) => ({
default: module.WindowBar,
})),
);
interface DefaultLayoutProps {
shell?: boolean;
shell?: boolean;
}
export const DefaultLayout = ({ shell }: DefaultLayoutProps) => {
const { windowBarStyle } = useWindowSettings();
const { opened, ...handlers } = useCommandPalette();
const { bindings } = useHotkeySettings();
const localSettings = isElectron() ? window.electron.localSettings : null;
const settings = useGeneralSettings();
const { setSettings } = useSettingsStoreActions();
const { windowBarStyle } = useWindowSettings();
const { opened, ...handlers } = useCommandPalette();
const { bindings } = useHotkeySettings();
const localSettings = isElectron() ? window.electron.localSettings : null;
const settings = useGeneralSettings();
const { setSettings } = useSettingsStoreActions();
const updateZoom = (increase: number) => {
const newVal = settings.zoomFactor + increase;
if (newVal > 300 || newVal < 50 || !isElectron()) return;
setSettings({
general: {
...settings,
zoomFactor: newVal,
},
});
const updateZoom = (increase: number) => {
const newVal = settings.zoomFactor + increase;
if (newVal > 300 || newVal < 50 || !isElectron()) return;
setSettings({
general: {
...settings,
zoomFactor: newVal,
},
});
localSettings?.setZoomFactor(settings.zoomFactor);
};
localSettings?.setZoomFactor(settings.zoomFactor);
};
localSettings?.setZoomFactor(settings.zoomFactor);
const zoomHotkeys: HotkeyItem[] = [
[bindings.zoomIn.hotkey, () => updateZoom(5)],
[bindings.zoomOut.hotkey, () => updateZoom(-5)],
];
const zoomHotkeys: HotkeyItem[] = [
[bindings.zoomIn.hotkey, () => updateZoom(5)],
[bindings.zoomOut.hotkey, () => updateZoom(-5)],
];
useHotkeys([
[bindings.globalSearch.hotkey, () => handlers.open()],
...(isElectron() ? zoomHotkeys : []),
]);
useHotkeys([
[bindings.globalSearch.hotkey, () => handlers.open()],
...(isElectron() ? zoomHotkeys : []),
]);
return (
<>
<Layout
id="default-layout"
windowBarStyle={windowBarStyle}
>
{windowBarStyle !== Platform.WEB && <WindowBar />}
<MainContent shell={shell} />
<PlayerBar />
</Layout>
<CommandPalette modalProps={{ handlers, opened }} />
</>
);
return (
<>
<Layout
id="default-layout"
windowBarStyle={windowBarStyle}
>
{windowBarStyle !== Platform.WEB && <WindowBar />}
<MainContent shell={shell} />
<PlayerBar />
</Layout>
<CommandPalette modalProps={{ handlers, opened }} />
</>
);
};
DefaultLayout.defaultProps = {
shell: false,
shell: false,
};

View file

@ -3,11 +3,11 @@ import { FullScreenPlayer } from '/@/renderer/features/player/components/full-sc
import { useFullScreenPlayerStore } from '/@/renderer/store';
export const FullScreenOverlay = () => {
const { expanded: isFullScreenPlayerExpanded } = useFullScreenPlayerStore();
const { expanded: isFullScreenPlayerExpanded } = useFullScreenPlayerStore();
return (
<AnimatePresence initial={false}>
{isFullScreenPlayerExpanded && <FullScreenPlayer />}
</AnimatePresence>
);
return (
<AnimatePresence initial={false}>
{isFullScreenPlayerExpanded && <FullScreenPlayer />}
</AnimatePresence>
);
};

View file

@ -6,33 +6,33 @@ import { Sidebar } from '/@/renderer/features/sidebar/components/sidebar';
import { useSidebarStore } from '/@/renderer/store';
const SidebarContainer = styled.aside`
position: relative;
grid-area: sidebar;
background: var(--sidebar-bg);
border-right: var(--sidebar-border);
position: relative;
grid-area: sidebar;
background: var(--sidebar-bg);
border-right: var(--sidebar-border);
`;
interface LeftSidebarProps {
isResizing: boolean;
startResizing: (direction: 'left' | 'right') => void;
isResizing: boolean;
startResizing: (direction: 'left' | 'right') => void;
}
export const LeftSidebar = ({ isResizing, startResizing }: LeftSidebarProps) => {
const sidebarRef = useRef<HTMLDivElement | null>(null);
const { collapsed } = useSidebarStore();
const sidebarRef = useRef<HTMLDivElement | null>(null);
const { collapsed } = useSidebarStore();
return (
<SidebarContainer id="sidebar">
<ResizeHandle
ref={sidebarRef}
isResizing={isResizing}
placement="right"
onMouseDown={(e) => {
e.preventDefault();
startResizing('left');
}}
/>
{collapsed ? <CollapsedSidebar /> : <Sidebar />}
</SidebarContainer>
);
return (
<SidebarContainer id="sidebar">
<ResizeHandle
ref={sidebarRef}
isResizing={isResizing}
placement="right"
onMouseDown={(e) => {
e.preventDefault();
startResizing('left');
}}
/>
{collapsed ? <CollapsedSidebar /> : <Sidebar />}
</SidebarContainer>
);
};

View file

@ -12,113 +12,117 @@ import { RightSidebar } from '/@/renderer/layouts/default-layout/right-sidebar';
import { Spinner } from '/@/renderer/components';
const SideDrawerQueue = lazy(() =>
import('/@/renderer/layouts/default-layout/side-drawer-queue').then((module) => ({
default: module.SideDrawerQueue,
})),
import('/@/renderer/layouts/default-layout/side-drawer-queue').then((module) => ({
default: module.SideDrawerQueue,
})),
);
const MINIMUM_SIDEBAR_WIDTH = 260;
const MainContentContainer = styled.div<{
leftSidebarWidth: string;
rightExpanded?: boolean;
rightSidebarWidth?: string;
shell?: boolean;
sidebarCollapsed?: boolean;
leftSidebarWidth: string;
rightExpanded?: boolean;
rightSidebarWidth?: string;
shell?: boolean;
sidebarCollapsed?: boolean;
}>`
position: relative;
display: ${(props) => (props.shell ? 'flex' : 'grid')};
grid-area: main-content;
grid-template-areas: 'sidebar . right-sidebar';
grid-template-rows: 1fr;
grid-template-columns: ${(props) => (props.sidebarCollapsed ? '80px' : props.leftSidebarWidth)} 1fr ${(
props,
) => props.rightExpanded && props.rightSidebarWidth};
position: relative;
display: ${(props) => (props.shell ? 'flex' : 'grid')};
grid-area: main-content;
grid-template-areas: 'sidebar . right-sidebar';
grid-template-rows: 1fr;
grid-template-columns: ${(props) => (props.sidebarCollapsed ? '80px' : props.leftSidebarWidth)} 1fr ${(
props,
) => props.rightExpanded && props.rightSidebarWidth};
gap: 0;
background: var(--main-bg);
gap: 0;
background: var(--main-bg);
`;
export const MainContent = ({ shell }: { shell?: boolean }) => {
const location = useLocation();
const { collapsed, leftWidth, rightWidth, rightExpanded } = useSidebarStore();
const { setSideBar } = useAppStoreActions();
const { sideQueueType, showQueueDrawerButton } = useGeneralSettings();
const [isResizing, setIsResizing] = useState(false);
const [isResizingRight, setIsResizingRight] = useState(false);
const location = useLocation();
const { collapsed, leftWidth, rightWidth, rightExpanded } = useSidebarStore();
const { setSideBar } = useAppStoreActions();
const { sideQueueType, showQueueDrawerButton } = useGeneralSettings();
const [isResizing, setIsResizing] = useState(false);
const [isResizingRight, setIsResizingRight] = useState(false);
const showSideQueue = rightExpanded && location.pathname !== AppRoute.NOW_PLAYING;
const rightSidebarRef = useRef<HTMLDivElement | null>(null);
const showSideQueue = rightExpanded && location.pathname !== AppRoute.NOW_PLAYING;
const rightSidebarRef = useRef<HTMLDivElement | null>(null);
const startResizing = useCallback((position: 'left' | 'right') => {
if (position === 'left') return setIsResizing(true);
return setIsResizingRight(true);
}, []);
const startResizing = useCallback((position: 'left' | 'right') => {
if (position === 'left') return setIsResizing(true);
return setIsResizingRight(true);
}, []);
const stopResizing = useCallback(() => {
setIsResizing(false);
setIsResizingRight(false);
}, []);
const stopResizing = useCallback(() => {
setIsResizing(false);
setIsResizingRight(false);
}, []);
const resize = useCallback(
(mouseMoveEvent: any) => {
if (isResizing) {
const width = mouseMoveEvent.clientX;
const constrainedWidth = `${constrainSidebarWidth(width)}px`;
const resize = useCallback(
(mouseMoveEvent: any) => {
if (isResizing) {
const width = mouseMoveEvent.clientX;
const constrainedWidth = `${constrainSidebarWidth(width)}px`;
if (width < MINIMUM_SIDEBAR_WIDTH - 100) {
setSideBar({ collapsed: true });
} else {
setSideBar({ collapsed: false, leftWidth: constrainedWidth });
}
} else if (isResizingRight) {
const start = Number(rightWidth.split('px')[0]);
const { left } = rightSidebarRef!.current!.getBoundingClientRect();
const width = `${constrainRightSidebarWidth(start + left - mouseMoveEvent.clientX)}px`;
setSideBar({ rightWidth: width });
}
},
[isResizing, isResizingRight, setSideBar, rightWidth],
);
if (width < MINIMUM_SIDEBAR_WIDTH - 100) {
setSideBar({ collapsed: true });
} else {
setSideBar({ collapsed: false, leftWidth: constrainedWidth });
}
} else if (isResizingRight) {
const start = Number(rightWidth.split('px')[0]);
const { left } = rightSidebarRef!.current!.getBoundingClientRect();
const width = `${constrainRightSidebarWidth(
start + left - mouseMoveEvent.clientX,
)}px`;
setSideBar({ rightWidth: width });
}
},
[isResizing, isResizingRight, setSideBar, rightWidth],
);
const throttledResize = useMemo(() => throttle(resize, 50), [resize]);
const throttledResize = useMemo(() => throttle(resize, 50), [resize]);
useEffect(() => {
window.addEventListener('mousemove', throttledResize);
window.addEventListener('mouseup', stopResizing);
return () => {
window.removeEventListener('mousemove', throttledResize);
window.removeEventListener('mouseup', stopResizing);
};
}, [throttledResize, stopResizing]);
useEffect(() => {
window.addEventListener('mousemove', throttledResize);
window.addEventListener('mouseup', stopResizing);
return () => {
window.removeEventListener('mousemove', throttledResize);
window.removeEventListener('mouseup', stopResizing);
};
}, [throttledResize, stopResizing]);
return (
<MainContentContainer
id="main-content"
leftSidebarWidth={leftWidth}
rightExpanded={showSideQueue && sideQueueType === 'sideQueue'}
rightSidebarWidth={rightWidth}
shell={shell}
sidebarCollapsed={collapsed}
>
{!shell && (
<>
<Suspense fallback={<></>}>{showQueueDrawerButton && <SideDrawerQueue />}</Suspense>
<FullScreenOverlay />
<LeftSidebar
isResizing={isResizing}
startResizing={startResizing}
/>
<RightSidebar
ref={rightSidebarRef}
isResizing={isResizingRight}
startResizing={startResizing}
/>
</>
)}
<Suspense fallback={<Spinner container />}>
<Outlet />
</Suspense>
</MainContentContainer>
);
return (
<MainContentContainer
id="main-content"
leftSidebarWidth={leftWidth}
rightExpanded={showSideQueue && sideQueueType === 'sideQueue'}
rightSidebarWidth={rightWidth}
shell={shell}
sidebarCollapsed={collapsed}
>
{!shell && (
<>
<Suspense fallback={<></>}>
{showQueueDrawerButton && <SideDrawerQueue />}
</Suspense>
<FullScreenOverlay />
<LeftSidebar
isResizing={isResizing}
startResizing={startResizing}
/>
<RightSidebar
ref={rightSidebarRef}
isResizing={isResizingRight}
startResizing={startResizing}
/>
</>
)}
<Suspense fallback={<Spinner container />}>
<Outlet />
</Suspense>
</MainContentContainer>
);
};

View file

@ -2,15 +2,15 @@ import styled from 'styled-components';
import { Playerbar } from '/@/renderer/features/player';
const PlayerbarContainer = styled.footer`
z-index: 200;
grid-area: player;
background: var(--playerbar-bg);
z-index: 200;
grid-area: player;
background: var(--playerbar-bg);
`;
export const PlayerBar = () => {
return (
<PlayerbarContainer id="player-bar">
<Playerbar />
</PlayerbarContainer>
);
return (
<PlayerbarContainer id="player-bar">
<Playerbar />
</PlayerbarContainer>
);
};

View file

@ -9,134 +9,137 @@ import { useGeneralSettings, useSidebarStore, useWindowSettings } from '/@/rende
import { Platform } from '/@/renderer/types';
const RightSidebarContainer = styled(motion.aside)`
position: relative;
grid-area: right-sidebar;
height: 100%;
background: var(--sidebar-bg);
border-left: var(--sidebar-border);
position: relative;
grid-area: right-sidebar;
height: 100%;
background: var(--sidebar-bg);
border-left: var(--sidebar-border);
`;
const queueSidebarVariants: Variants = {
closed: (rightWidth) => ({
transition: { duration: 0.5 },
width: rightWidth,
x: 1000,
zIndex: 120,
}),
open: (rightWidth) => ({
transition: {
duration: 0.5,
ease: 'anticipate',
},
width: rightWidth,
x: 0,
zIndex: 120,
}),
closed: (rightWidth) => ({
transition: { duration: 0.5 },
width: rightWidth,
x: 1000,
zIndex: 120,
}),
open: (rightWidth) => ({
transition: {
duration: 0.5,
ease: 'anticipate',
},
width: rightWidth,
x: 0,
zIndex: 120,
}),
};
const QueueDrawer = styled(motion.div)`
background: var(--main-bg);
border: 3px solid var(--generic-border-color);
border-radius: 10px;
background: var(--main-bg);
border: 3px solid var(--generic-border-color);
border-radius: 10px;
`;
const queueDrawerVariants: Variants = {
closed: (windowBarStyle) => ({
height:
windowBarStyle === Platform.WINDOWS || Platform.MACOS
? 'calc(100vh - 205px)'
: 'calc(100vh - 175px)',
position: 'absolute',
right: 0,
top: '75px',
transition: {
duration: 0.4,
ease: 'anticipate',
},
width: '450px',
x: '50vw',
}),
open: (windowBarStyle) => ({
boxShadow: '0px 0px 10px 0px rgba(0, 0, 0, 0.8)',
height:
windowBarStyle === Platform.WINDOWS || Platform.MACOS
? 'calc(100vh - 205px)'
: 'calc(100vh - 175px)',
position: 'absolute',
right: '20px',
top: '75px',
transition: {
damping: 10,
delay: 0,
duration: 0.4,
ease: 'anticipate',
mass: 0.5,
},
width: '450px',
x: 0,
zIndex: 120,
}),
closed: (windowBarStyle) => ({
height:
windowBarStyle === Platform.WINDOWS || Platform.MACOS
? 'calc(100vh - 205px)'
: 'calc(100vh - 175px)',
position: 'absolute',
right: 0,
top: '75px',
transition: {
duration: 0.4,
ease: 'anticipate',
},
width: '450px',
x: '50vw',
}),
open: (windowBarStyle) => ({
boxShadow: '0px 0px 10px 0px rgba(0, 0, 0, 0.8)',
height:
windowBarStyle === Platform.WINDOWS || Platform.MACOS
? 'calc(100vh - 205px)'
: 'calc(100vh - 175px)',
position: 'absolute',
right: '20px',
top: '75px',
transition: {
damping: 10,
delay: 0,
duration: 0.4,
ease: 'anticipate',
mass: 0.5,
},
width: '450px',
x: 0,
zIndex: 120,
}),
};
interface RightSidebarProps {
isResizing: boolean;
startResizing: (direction: 'left' | 'right') => void;
isResizing: boolean;
startResizing: (direction: 'left' | 'right') => void;
}
export const RightSidebar = forwardRef(
({ isResizing: isResizingRight, startResizing }: RightSidebarProps, ref: Ref<HTMLDivElement>) => {
const { windowBarStyle } = useWindowSettings();
const { rightWidth, rightExpanded } = useSidebarStore();
const { sideQueueType } = useGeneralSettings();
const location = useLocation();
const showSideQueue = rightExpanded && location.pathname !== AppRoute.NOW_PLAYING;
(
{ isResizing: isResizingRight, startResizing }: RightSidebarProps,
ref: Ref<HTMLDivElement>,
) => {
const { windowBarStyle } = useWindowSettings();
const { rightWidth, rightExpanded } = useSidebarStore();
const { sideQueueType } = useGeneralSettings();
const location = useLocation();
const showSideQueue = rightExpanded && location.pathname !== AppRoute.NOW_PLAYING;
return (
<AnimatePresence
key="queue-sidebar"
presenceAffectsLayout
initial={false}
mode="sync"
>
{showSideQueue && (
<>
{sideQueueType === 'sideQueue' ? (
<RightSidebarContainer
return (
<AnimatePresence
key="queue-sidebar"
animate="open"
custom={rightWidth}
exit="closed"
id="sidebar-queue"
initial="closed"
variants={queueSidebarVariants}
>
<ResizeHandle
ref={ref}
isResizing={isResizingRight}
placement="left"
onMouseDown={(e) => {
e.preventDefault();
startResizing('right');
}}
/>
<SidebarPlayQueue />
</RightSidebarContainer>
) : (
<QueueDrawer
key="queue-drawer"
animate="open"
custom={windowBarStyle}
exit="closed"
id="drawer-queue"
initial="closed"
variants={queueDrawerVariants}
>
<DrawerPlayQueue />
</QueueDrawer>
)}
</>
)}
</AnimatePresence>
);
},
presenceAffectsLayout
initial={false}
mode="sync"
>
{showSideQueue && (
<>
{sideQueueType === 'sideQueue' ? (
<RightSidebarContainer
key="queue-sidebar"
animate="open"
custom={rightWidth}
exit="closed"
id="sidebar-queue"
initial="closed"
variants={queueSidebarVariants}
>
<ResizeHandle
ref={ref}
isResizing={isResizingRight}
placement="left"
onMouseDown={(e) => {
e.preventDefault();
startResizing('right');
}}
/>
<SidebarPlayQueue />
</RightSidebarContainer>
) : (
<QueueDrawer
key="queue-drawer"
animate="open"
custom={windowBarStyle}
exit="closed"
id="drawer-queue"
initial="closed"
variants={queueDrawerVariants}
>
<DrawerPlayQueue />
</QueueDrawer>
)}
</>
)}
</AnimatePresence>
);
},
);

View file

@ -10,132 +10,132 @@ import { useAppStore, useSidebarStore } from '/@/renderer/store';
import { Platform } from '/@/renderer/types';
const QueueDrawerArea = styled(motion.div)`
position: absolute;
top: 50%;
right: 25px;
z-index: 100;
display: flex;
align-items: center;
width: 20px;
height: 30px;
user-select: none;
position: absolute;
top: 50%;
right: 25px;
z-index: 100;
display: flex;
align-items: center;
width: 20px;
height: 30px;
user-select: none;
`;
const QueueDrawer = styled(motion.div)`
background: var(--main-bg);
border: 3px solid var(--generic-border-color);
border-radius: 10px;
background: var(--main-bg);
border: 3px solid var(--generic-border-color);
border-radius: 10px;
`;
const queueDrawerVariants: Variants = {
closed: (windowBarStyle) => ({
height:
windowBarStyle === Platform.WINDOWS || Platform.MACOS
? 'calc(100vh - 205px)'
: 'calc(100vh - 175px)',
position: 'absolute',
right: 0,
top: '75px',
transition: {
duration: 0.4,
ease: 'anticipate',
},
width: '450px',
x: '50vw',
}),
open: (windowBarStyle) => ({
boxShadow: '0px 0px 10px 0px rgba(0, 0, 0, 0.8)',
height:
windowBarStyle === Platform.WINDOWS || Platform.MACOS
? 'calc(100vh - 205px)'
: 'calc(100vh - 175px)',
position: 'absolute',
right: '20px',
top: '75px',
transition: {
damping: 10,
delay: 0,
duration: 0.4,
ease: 'anticipate',
mass: 0.5,
},
width: '450px',
x: 0,
zIndex: 120,
}),
closed: (windowBarStyle) => ({
height:
windowBarStyle === Platform.WINDOWS || Platform.MACOS
? 'calc(100vh - 205px)'
: 'calc(100vh - 175px)',
position: 'absolute',
right: 0,
top: '75px',
transition: {
duration: 0.4,
ease: 'anticipate',
},
width: '450px',
x: '50vw',
}),
open: (windowBarStyle) => ({
boxShadow: '0px 0px 10px 0px rgba(0, 0, 0, 0.8)',
height:
windowBarStyle === Platform.WINDOWS || Platform.MACOS
? 'calc(100vh - 205px)'
: 'calc(100vh - 175px)',
position: 'absolute',
right: '20px',
top: '75px',
transition: {
damping: 10,
delay: 0,
duration: 0.4,
ease: 'anticipate',
mass: 0.5,
},
width: '450px',
x: 0,
zIndex: 120,
}),
};
const queueDrawerButtonVariants: Variants = {
hidden: {
opacity: 0,
transition: { duration: 0.2 },
x: 100,
},
visible: {
opacity: 0.5,
transition: { duration: 0.1, ease: 'anticipate' },
x: 0,
},
hidden: {
opacity: 0,
transition: { duration: 0.2 },
x: 100,
},
visible: {
opacity: 0.5,
transition: { duration: 0.1, ease: 'anticipate' },
x: 0,
},
};
export const SideDrawerQueue = () => {
const location = useLocation();
const [drawer, drawerHandler] = useDisclosure(false);
const { rightExpanded } = useSidebarStore();
const location = useLocation();
const [drawer, drawerHandler] = useDisclosure(false);
const { rightExpanded } = useSidebarStore();
const drawerTimeout = useTimeout(() => drawerHandler.open(), 500);
const drawerTimeout = useTimeout(() => drawerHandler.open(), 500);
const handleEnterDrawerButton = useCallback(() => {
drawerTimeout.start();
}, [drawerTimeout]);
const handleEnterDrawerButton = useCallback(() => {
drawerTimeout.start();
}, [drawerTimeout]);
const handleLeaveDrawerButton = useCallback(() => {
drawerTimeout.clear();
}, [drawerTimeout]);
const handleLeaveDrawerButton = useCallback(() => {
drawerTimeout.clear();
}, [drawerTimeout]);
const isQueueDrawerButtonVisible =
!rightExpanded && !drawer && location.pathname !== AppRoute.NOW_PLAYING;
const isQueueDrawerButtonVisible =
!rightExpanded && !drawer && location.pathname !== AppRoute.NOW_PLAYING;
return (
<>
<AnimatePresence
initial={false}
mode="wait"
>
{isQueueDrawerButtonVisible && (
<QueueDrawerArea
key="queue-drawer-button"
animate="visible"
exit="hidden"
initial="hidden"
variants={queueDrawerButtonVariants}
whileHover={{ opacity: 1, scale: 2, transition: { duration: 0.5 } }}
onMouseEnter={handleEnterDrawerButton}
onMouseLeave={handleLeaveDrawerButton}
>
<TbArrowBarLeft size={12} />
</QueueDrawerArea>
)}
return (
<>
<AnimatePresence
initial={false}
mode="wait"
>
{isQueueDrawerButtonVisible && (
<QueueDrawerArea
key="queue-drawer-button"
animate="visible"
exit="hidden"
initial="hidden"
variants={queueDrawerButtonVariants}
whileHover={{ opacity: 1, scale: 2, transition: { duration: 0.5 } }}
onMouseEnter={handleEnterDrawerButton}
onMouseLeave={handleLeaveDrawerButton}
>
<TbArrowBarLeft size={12} />
</QueueDrawerArea>
)}
{drawer && (
<QueueDrawer
key="queue-drawer"
animate="open"
exit="closed"
initial="closed"
variants={queueDrawerVariants}
onMouseLeave={() => {
// The drawer will close due to the delay when setting isReorderingQueue
setTimeout(() => {
if (useAppStore.getState().isReorderingQueue) return;
drawerHandler.close();
}, 50);
}}
>
<DrawerPlayQueue />
</QueueDrawer>
)}
</AnimatePresence>
</>
);
{drawer && (
<QueueDrawer
key="queue-drawer"
animate="open"
exit="closed"
initial="closed"
variants={queueDrawerVariants}
onMouseLeave={() => {
// The drawer will close due to the delay when setting isReorderingQueue
setTimeout(() => {
if (useAppStore.getState().isReorderingQueue) return;
drawerHandler.close();
}, 50);
}}
>
<DrawerPlayQueue />
</QueueDrawer>
)}
</AnimatePresence>
</>
);
};

View file

@ -14,49 +14,49 @@ import macMinHover from './assets/min-mac-hover.png';
import macMin from './assets/min-mac.png';
const WindowsContainer = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
width: 100vw;
color: var(--window-bar-fg);
background-color: var(--window-bar-bg);
-webkit-app-region: drag;
display: flex;
align-items: center;
justify-content: space-between;
width: 100vw;
color: var(--window-bar-fg);
background-color: var(--window-bar-bg);
-webkit-app-region: drag;
`;
const WindowsButtonGroup = styled.div`
display: flex;
width: 130px;
height: 100%;
-webkit-app-region: no-drag;
display: flex;
width: 130px;
height: 100%;
-webkit-app-region: no-drag;
`;
const WindowsButton = styled.div<{ $exit?: boolean }>`
display: flex;
flex: 1;
align-items: center;
justify-content: center;
-webkit-app-region: no-drag;
width: 50px;
height: 30px;
display: flex;
flex: 1;
align-items: center;
justify-content: center;
-webkit-app-region: no-drag;
width: 50px;
height: 30px;
img {
width: 35%;
height: 50%;
}
img {
width: 35%;
height: 50%;
}
&:hover {
background: ${({ $exit }) => ($exit ? 'var(--danger-color)' : 'rgba(125, 125, 125, 30%)')};
}
&:hover {
background: ${({ $exit }) => ($exit ? 'var(--danger-color)' : 'rgba(125, 125, 125, 30%)')};
}
`;
const PlayerStatusContainer = styled.div`
display: flex;
gap: 0.5rem;
max-width: 45vw;
padding-left: 1rem;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
display: flex;
gap: 0.5rem;
max-width: 45vw;
padding-left: 1rem;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
`;
const browser = isElectron() ? window.electron.browser : null;
@ -66,192 +66,193 @@ const maximize = () => browser.maximize();
const unmaximize = () => browser.unmaximize();
interface WindowBarControlsProps {
controls: {
handleClose: () => void;
handleMaximize: () => void;
handleMinimize: () => void;
};
title: string;
controls: {
handleClose: () => void;
handleMaximize: () => void;
handleMinimize: () => void;
};
title: string;
}
const WindowsControls = ({ controls, title }: WindowBarControlsProps) => {
const { handleClose, handleMaximize, handleMinimize } = controls;
const { handleClose, handleMaximize, handleMinimize } = controls;
return (
<WindowsContainer>
<PlayerStatusContainer>
<img
alt=""
height={18}
src={appIcon}
width={18}
/>
{title}
</PlayerStatusContainer>
<WindowsButtonGroup>
<WindowsButton
role="button"
onClick={handleMinimize}
>
<RiSubtractLine size={19} />
</WindowsButton>
<WindowsButton
role="button"
onClick={handleMaximize}
>
<RiCheckboxBlankLine size={13} />
</WindowsButton>
<WindowsButton
$exit
role="button"
onClick={handleClose}
>
<RiCloseLine size={19} />
</WindowsButton>
</WindowsButtonGroup>
</WindowsContainer>
);
return (
<WindowsContainer>
<PlayerStatusContainer>
<img
alt=""
height={18}
src={appIcon}
width={18}
/>
{title}
</PlayerStatusContainer>
<WindowsButtonGroup>
<WindowsButton
role="button"
onClick={handleMinimize}
>
<RiSubtractLine size={19} />
</WindowsButton>
<WindowsButton
role="button"
onClick={handleMaximize}
>
<RiCheckboxBlankLine size={13} />
</WindowsButton>
<WindowsButton
$exit
role="button"
onClick={handleClose}
>
<RiCloseLine size={19} />
</WindowsButton>
</WindowsButtonGroup>
</WindowsContainer>
);
};
const MacOsContainer = styled.div`
display: flex;
align-items: center;
justify-content: center;
width: 100vw;
-webkit-app-region: drag;
color: var(--window-bar-fg);
background-color: var(--window-bar-bg);
display: flex;
align-items: center;
justify-content: center;
width: 100vw;
-webkit-app-region: drag;
color: var(--window-bar-fg);
background-color: var(--window-bar-bg);
`;
const MacOsButtonGroup = styled.div`
position: absolute;
top: 5px;
left: 0.5rem;
display: grid;
grid-template-columns: repeat(3, 20px);
height: 100%;
position: absolute;
top: 5px;
left: 0.5rem;
display: grid;
grid-template-columns: repeat(3, 20px);
height: 100%;
-webkit-app-region: no-drag;
-webkit-app-region: no-drag;
`;
export const MacOsButton = styled.div<{
maxButton?: boolean;
minButton?: boolean;
restoreButton?: boolean;
maxButton?: boolean;
minButton?: boolean;
restoreButton?: boolean;
}>`
grid-row: 1 / span 1;
grid-column: ${(props) => (props.minButton ? 2 : props.maxButton || props.restoreButton ? 3 : 1)};
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
user-select: none;
grid-row: 1 / span 1;
grid-column: ${(props) =>
props.minButton ? 2 : props.maxButton || props.restoreButton ? 3 : 1};
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
user-select: none;
img {
width: 18px;
height: 18px;
}
img {
width: 18px;
height: 18px;
}
`;
const MacOsControls = ({ controls, title }: WindowBarControlsProps) => {
const { handleClose, handleMaximize, handleMinimize } = controls;
const { handleClose, handleMaximize, handleMinimize } = controls;
const [hoverMin, setHoverMin] = useState(false);
const [hoverMax, setHoverMax] = useState(false);
const [hoverClose, setHoverClose] = useState(false);
const [hoverMin, setHoverMin] = useState(false);
const [hoverMax, setHoverMax] = useState(false);
const [hoverClose, setHoverClose] = useState(false);
return (
<MacOsContainer>
<MacOsButtonGroup>
<MacOsButton
minButton
className="button"
id="min-button"
onClick={handleMinimize}
onMouseLeave={() => setHoverMin(false)}
onMouseOver={() => setHoverMin(true)}
>
<img
alt=""
className="icon"
draggable="false"
src={hoverMin ? macMinHover : macMin}
/>
</MacOsButton>
<MacOsButton
maxButton
className="button"
id="max-button"
onClick={handleMaximize}
onMouseLeave={() => setHoverMax(false)}
onMouseOver={() => setHoverMax(true)}
>
<img
alt=""
className="icon"
draggable="false"
src={hoverMax ? macMaxHover : macMax}
/>
</MacOsButton>
<MacOsButton
className="button"
id="close-button"
onClick={handleClose}
onMouseLeave={() => setHoverClose(false)}
onMouseOver={() => setHoverClose(true)}
>
<img
alt=""
className="icon"
draggable="false"
src={hoverClose ? macCloseHover : macClose}
/>
</MacOsButton>
</MacOsButtonGroup>
<PlayerStatusContainer>{title}</PlayerStatusContainer>
</MacOsContainer>
);
return (
<MacOsContainer>
<MacOsButtonGroup>
<MacOsButton
minButton
className="button"
id="min-button"
onClick={handleMinimize}
onMouseLeave={() => setHoverMin(false)}
onMouseOver={() => setHoverMin(true)}
>
<img
alt=""
className="icon"
draggable="false"
src={hoverMin ? macMinHover : macMin}
/>
</MacOsButton>
<MacOsButton
maxButton
className="button"
id="max-button"
onClick={handleMaximize}
onMouseLeave={() => setHoverMax(false)}
onMouseOver={() => setHoverMax(true)}
>
<img
alt=""
className="icon"
draggable="false"
src={hoverMax ? macMaxHover : macMax}
/>
</MacOsButton>
<MacOsButton
className="button"
id="close-button"
onClick={handleClose}
onMouseLeave={() => setHoverClose(false)}
onMouseOver={() => setHoverClose(true)}
>
<img
alt=""
className="icon"
draggable="false"
src={hoverClose ? macCloseHover : macClose}
/>
</MacOsButton>
</MacOsButtonGroup>
<PlayerStatusContainer>{title}</PlayerStatusContainer>
</MacOsContainer>
);
};
export const WindowBar = () => {
const playerStatus = useCurrentStatus();
const { currentSong, index, length } = useQueueStatus();
const { windowBarStyle } = useWindowSettings();
const playerStatus = useCurrentStatus();
const { currentSong, index, length } = useQueueStatus();
const { windowBarStyle } = useWindowSettings();
const statusString = playerStatus === PlayerStatus.PAUSED ? '(Paused) ' : '';
const queueString = length ? `(${index + 1} / ${length}) ` : '';
const title = length ? `${statusString}${queueString}${currentSong?.name}` : 'Feishin';
document.title = title;
const statusString = playerStatus === PlayerStatus.PAUSED ? '(Paused) ' : '';
const queueString = length ? `(${index + 1} / ${length}) ` : '';
const title = length ? `${statusString}${queueString}${currentSong?.name}` : 'Feishin';
document.title = title;
const [max, setMax] = useState(false);
const [max, setMax] = useState(false);
const handleMinimize = () => minimize();
const handleMinimize = () => minimize();
const handleMaximize = useCallback(() => {
if (max) {
unmaximize();
} else {
maximize();
}
setMax(!max);
}, [max]);
const handleMaximize = useCallback(() => {
if (max) {
unmaximize();
} else {
maximize();
}
setMax(!max);
}, [max]);
const handleClose = useCallback(() => close(), []);
const handleClose = useCallback(() => close(), []);
return (
<>
{windowBarStyle === Platform.WINDOWS && (
<WindowsControls
controls={{ handleClose, handleMaximize, handleMinimize }}
title={title}
/>
)}
{windowBarStyle === Platform.MACOS && (
<MacOsControls
controls={{ handleClose, handleMaximize, handleMinimize }}
title={title}
/>
)}
</>
);
return (
<>
{windowBarStyle === Platform.WINDOWS && (
<WindowsControls
controls={{ handleClose, handleMaximize, handleMinimize }}
title={title}
/>
)}
{windowBarStyle === Platform.MACOS && (
<MacOsControls
controls={{ handleClose, handleMaximize, handleMinimize }}
title={title}
/>
)}
</>
);
};