mirror of
https://github.com/antebudimir/feishin.git
synced 2026-01-01 02:13:33 +00:00
Migrate to Mantine v8 and Design Changes (#961)
* mantine v8 migration * various design changes and improvements
This commit is contained in:
parent
bea55d48a8
commit
c1330d92b2
473 changed files with 12469 additions and 11607 deletions
14
src/renderer/layouts/auth-layout.module.css
Normal file
14
src/renderer/layouts/auth-layout.module.css
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
.window-titlebar-container {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
user-select: none;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
.content-container {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
|
|
@ -1,32 +1,18 @@
|
|||
import { Outlet } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import styles from './auth-layout.module.css';
|
||||
|
||||
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;
|
||||
`;
|
||||
|
||||
const ContentContainer = styled.div`
|
||||
display: flex;
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
export const AuthLayout = () => {
|
||||
return (
|
||||
<>
|
||||
<WindowsTitlebarContainer>
|
||||
<div className={styles.windowTitlebarContainer}>
|
||||
<Titlebar />
|
||||
</WindowsTitlebarContainer>
|
||||
<ContentContainer>
|
||||
</div>
|
||||
<div className={styles.contentContainer}>
|
||||
<Outlet />
|
||||
</ContentContainer>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
20
src/renderer/layouts/default-layout.module.css
Normal file
20
src/renderer/layouts/default-layout.module.css
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
.layout {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
'window-bar'
|
||||
'main-content'
|
||||
'player';
|
||||
grid-template-rows: 0 calc(100vh - 90px) 90px;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.windows {
|
||||
grid-template-rows: 30px calc(100vh - 120px) 90px;
|
||||
}
|
||||
|
||||
.macos {
|
||||
grid-template-rows: 30px calc(100vh - 120px) 90px;
|
||||
}
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
import { HotkeyItem, useHotkeys } from '@mantine/hooks';
|
||||
import clsx from 'clsx';
|
||||
import isElectron from 'is-electron';
|
||||
import { lazy } from 'react';
|
||||
import { useNavigate } from 'react-router';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import styles from './default-layout.module.css';
|
||||
|
||||
import { CommandPalette } from '/@/renderer/features/search/components/command-palette';
|
||||
import { MainContent } from '/@/renderer/layouts/default-layout/main-content';
|
||||
|
|
@ -26,22 +28,6 @@ if (!isElectron()) {
|
|||
});
|
||||
}
|
||||
|
||||
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;
|
||||
`;
|
||||
|
||||
const WindowBar = lazy(() =>
|
||||
import('/@/renderer/layouts/window-bar').then((module) => ({
|
||||
default: module.WindowBar,
|
||||
|
|
@ -88,14 +74,17 @@ export const DefaultLayout = ({ shell }: DefaultLayoutProps) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Layout
|
||||
$windowBarStyle={windowBarStyle}
|
||||
<div
|
||||
className={clsx(styles.layout, {
|
||||
[styles.macos]: windowBarStyle === Platform.MACOS,
|
||||
[styles.windows]: windowBarStyle === Platform.WINDOWS,
|
||||
})}
|
||||
id="default-layout"
|
||||
>
|
||||
{windowBarStyle !== Platform.WEB && <WindowBar />}
|
||||
<MainContent shell={shell} />
|
||||
<PlayerBar />
|
||||
</Layout>
|
||||
</div>
|
||||
<CommandPalette modalProps={{ handlers, opened }} />
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { AnimatePresence } from 'framer-motion';
|
||||
import { AnimatePresence } from 'motion/react';
|
||||
|
||||
import { FullScreenPlayer } from '/@/renderer/features/player/components/full-screen-player';
|
||||
import { useFullScreenPlayerStore } from '/@/renderer/store';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
.container {
|
||||
position: relative;
|
||||
grid-area: sidebar;
|
||||
border-right: 1px solid alpha(var(--theme-colors-border), 0.3);
|
||||
}
|
||||
|
|
@ -1,18 +1,12 @@
|
|||
import { useRef } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import styles from './left-sidebar.module.css';
|
||||
|
||||
import { ResizeHandle } from '/@/renderer/features/shared';
|
||||
import { CollapsedSidebar } from '/@/renderer/features/sidebar/components/collapsed-sidebar';
|
||||
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);
|
||||
`;
|
||||
|
||||
interface LeftSidebarProps {
|
||||
isResizing: boolean;
|
||||
startResizing: (direction: 'left' | 'right') => void;
|
||||
|
|
@ -23,17 +17,20 @@ export const LeftSidebar = ({ isResizing, startResizing }: LeftSidebarProps) =>
|
|||
const { collapsed } = useSidebarStore();
|
||||
|
||||
return (
|
||||
<SidebarContainer id="sidebar">
|
||||
<aside
|
||||
className={styles.container}
|
||||
id="sidebar"
|
||||
>
|
||||
<ResizeHandle
|
||||
$isResizing={isResizing}
|
||||
$placement="right"
|
||||
isResizing={isResizing}
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
startResizing('left');
|
||||
}}
|
||||
placement="right"
|
||||
ref={sidebarRef}
|
||||
/>
|
||||
{collapsed ? <CollapsedSidebar /> : <Sidebar />}
|
||||
</SidebarContainer>
|
||||
</aside>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
28
src/renderer/layouts/default-layout/main-content.module.css
Normal file
28
src/renderer/layouts/default-layout/main-content.module.css
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
.main-content-container {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-area: main-content;
|
||||
grid-template-areas: 'sidebar . right-sidebar';
|
||||
grid-template-rows: 1fr;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.main-content-container.shell {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.main-content-container.sidebar-collapsed {
|
||||
grid-template-columns: 80px 1fr;
|
||||
}
|
||||
|
||||
.main-content-container.sidebar-expanded {
|
||||
grid-template-columns: var(--sidebar-width) 1fr;
|
||||
}
|
||||
|
||||
.main-content-container.right-expanded {
|
||||
grid-template-columns: var(--sidebar-width) 1fr var(--right-sidebar-width);
|
||||
}
|
||||
|
||||
.main-content-container.sidebar-collapsed.right-expanded {
|
||||
grid-template-columns: 80px 1fr var(--right-sidebar-width);
|
||||
}
|
||||
|
|
@ -1,9 +1,20 @@
|
|||
import { throttle } from 'lodash';
|
||||
import { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import clsx from 'clsx';
|
||||
import throttle from 'lodash/throttle';
|
||||
import { motion } from 'motion/react';
|
||||
import {
|
||||
CSSProperties,
|
||||
lazy,
|
||||
Suspense,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { Outlet, useLocation } from 'react-router';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { Spinner } from '/@/renderer/components';
|
||||
import styles from './main-content.module.css';
|
||||
|
||||
import { FullScreenOverlay } from '/@/renderer/layouts/default-layout/full-screen-overlay';
|
||||
import { LeftSidebar } from '/@/renderer/layouts/default-layout/left-sidebar';
|
||||
import { RightSidebar } from '/@/renderer/layouts/default-layout/right-sidebar';
|
||||
|
|
@ -11,6 +22,7 @@ import { AppRoute } from '/@/renderer/router/routes';
|
|||
import { useAppStoreActions, useSidebarStore } from '/@/renderer/store';
|
||||
import { useGeneralSettings } from '/@/renderer/store/settings.store';
|
||||
import { constrainRightSidebarWidth, constrainSidebarWidth } from '/@/renderer/utils';
|
||||
import { Spinner } from '/@/shared/components/spinner/spinner';
|
||||
|
||||
const SideDrawerQueue = lazy(() =>
|
||||
import('/@/renderer/layouts/default-layout/side-drawer-queue').then((module) => ({
|
||||
|
|
@ -20,26 +32,6 @@ const SideDrawerQueue = lazy(() =>
|
|||
|
||||
const MINIMUM_SIDEBAR_WIDTH = 260;
|
||||
|
||||
const MainContentContainer = styled.div<{
|
||||
$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};
|
||||
|
||||
gap: 0;
|
||||
background: var(--main-bg);
|
||||
`;
|
||||
|
||||
export const MainContent = ({ shell }: { shell?: boolean }) => {
|
||||
const location = useLocation();
|
||||
const { collapsed, leftWidth, rightExpanded, rightWidth } = useSidebarStore();
|
||||
|
|
@ -96,13 +88,20 @@ export const MainContent = ({ shell }: { shell?: boolean }) => {
|
|||
}, [throttledResize, stopResizing]);
|
||||
|
||||
return (
|
||||
<MainContentContainer
|
||||
$leftSidebarWidth={leftWidth}
|
||||
$rightExpanded={showSideQueue && sideQueueType === 'sideQueue'}
|
||||
$rightSidebarWidth={rightWidth}
|
||||
$shell={shell}
|
||||
$sidebarCollapsed={collapsed}
|
||||
<motion.div
|
||||
className={clsx(styles.mainContentContainer, {
|
||||
[styles.rightExpanded]: showSideQueue && sideQueueType === 'sideQueue',
|
||||
[styles.shell]: shell,
|
||||
[styles.sidebarCollapsed]: collapsed,
|
||||
[styles.sidebarExpanded]: !collapsed,
|
||||
})}
|
||||
id="main-content"
|
||||
style={
|
||||
{
|
||||
'--right-sidebar-width': rightWidth,
|
||||
'--sidebar-width': leftWidth,
|
||||
} as CSSProperties
|
||||
}
|
||||
>
|
||||
{!shell && (
|
||||
<>
|
||||
|
|
@ -124,6 +123,6 @@ export const MainContent = ({ shell }: { shell?: boolean }) => {
|
|||
<Suspense fallback={<Spinner container />}>
|
||||
<Outlet />
|
||||
</Suspense>
|
||||
</MainContentContainer>
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
12
src/renderer/layouts/default-layout/player-bar.module.css
Normal file
12
src/renderer/layouts/default-layout/player-bar.module.css
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
.container {
|
||||
z-index: 200;
|
||||
grid-area: player;
|
||||
background: darken(var(--theme-colors-background), 10%);
|
||||
transition: background 0.5s;
|
||||
}
|
||||
|
||||
.open-drawer {
|
||||
&:hover {
|
||||
background: darken(var(--theme-colors-background), 20%);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +1,22 @@
|
|||
import styled from 'styled-components';
|
||||
import clsx from 'clsx';
|
||||
|
||||
import styles from './player-bar.module.css';
|
||||
|
||||
import { Playerbar } from '/@/renderer/features/player';
|
||||
import { useGeneralSettings } from '/@/renderer/store/settings.store';
|
||||
|
||||
interface PlayerbarContainerProps {
|
||||
$drawerEffect: boolean;
|
||||
}
|
||||
|
||||
const PlayerbarContainer = styled.footer<PlayerbarContainerProps>`
|
||||
z-index: 200;
|
||||
grid-area: player;
|
||||
background: var(--playerbar-bg);
|
||||
transition: background 0.5s;
|
||||
|
||||
${(props) =>
|
||||
props.$drawerEffect &&
|
||||
`
|
||||
&:hover {
|
||||
background: var(--playerbar-bg-active);
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
export const PlayerBar = () => {
|
||||
const { playerbarOpenDrawer } = useGeneralSettings();
|
||||
|
||||
return (
|
||||
<PlayerbarContainer
|
||||
$drawerEffect={playerbarOpenDrawer}
|
||||
<div
|
||||
className={clsx({
|
||||
[styles.container]: true,
|
||||
[styles.openDrawer]: playerbarOpenDrawer,
|
||||
})}
|
||||
id="player-bar"
|
||||
>
|
||||
<Playerbar />
|
||||
</PlayerbarContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
15
src/renderer/layouts/default-layout/right-sidebar.module.css
Normal file
15
src/renderer/layouts/default-layout/right-sidebar.module.css
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
.right-sidebar-container {
|
||||
position: relative;
|
||||
grid-area: right-sidebar;
|
||||
height: 100%;
|
||||
border-left: 1px solid alpha(var(--theme-colors-border), 0.3);
|
||||
|
||||
.current-song-cell:not(.current-playlist-song-cell) svg {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.queue-drawer {
|
||||
background: var(--theme-colors-background);
|
||||
border-radius: var(--theme-radius-lg);
|
||||
}
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
import { AnimatePresence, motion, Variants } from 'framer-motion';
|
||||
import { AnimatePresence, motion, Variants } from 'motion/react';
|
||||
import { forwardRef, Ref } from 'react';
|
||||
import { useLocation } from 'react-router';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import styles from './right-sidebar.module.css';
|
||||
|
||||
import { DrawerPlayQueue, SidebarPlayQueue } from '/@/renderer/features/now-playing';
|
||||
import { ResizeHandle } from '/@/renderer/features/shared';
|
||||
|
|
@ -9,18 +10,6 @@ import { AppRoute } from '/@/renderer/router/routes';
|
|||
import { useGeneralSettings, useSidebarStore, useWindowSettings } from '/@/renderer/store';
|
||||
import { Platform } from '/@/shared/types/types';
|
||||
|
||||
const RightSidebarContainer = styled(motion.aside)`
|
||||
position: relative;
|
||||
grid-area: right-sidebar;
|
||||
height: 100%;
|
||||
background: var(--sidebar-bg);
|
||||
border-left: var(--sidebar-border);
|
||||
|
||||
.current-song-cell:not(.current-playlist-song-cell) svg {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const queueSidebarVariants: Variants = {
|
||||
closed: (rightWidth) => ({
|
||||
transition: { duration: 0.5 },
|
||||
|
|
@ -39,12 +28,6 @@ const queueSidebarVariants: Variants = {
|
|||
}),
|
||||
};
|
||||
|
||||
const QueueDrawer = styled(motion.div)`
|
||||
background: var(--main-bg);
|
||||
border: 3px solid var(--generic-border-color);
|
||||
border-radius: 10px;
|
||||
`;
|
||||
|
||||
const queueDrawerVariants: Variants = {
|
||||
closed: (windowBarStyle) => ({
|
||||
height:
|
||||
|
|
@ -109,8 +92,9 @@ export const RightSidebar = forwardRef(
|
|||
{showSideQueue && (
|
||||
<>
|
||||
{sideQueueType === 'sideQueue' ? (
|
||||
<RightSidebarContainer
|
||||
<motion.aside
|
||||
animate="open"
|
||||
className={styles.rightSidebarContainer}
|
||||
custom={rightWidth}
|
||||
exit="closed"
|
||||
id="sidebar-queue"
|
||||
|
|
@ -119,19 +103,20 @@ export const RightSidebar = forwardRef(
|
|||
variants={queueSidebarVariants}
|
||||
>
|
||||
<ResizeHandle
|
||||
$isResizing={isResizingRight}
|
||||
$placement="left"
|
||||
isResizing={isResizingRight}
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
startResizing('right');
|
||||
}}
|
||||
placement="left"
|
||||
ref={ref}
|
||||
/>
|
||||
<SidebarPlayQueue />
|
||||
</RightSidebarContainer>
|
||||
</motion.aside>
|
||||
) : (
|
||||
<QueueDrawer
|
||||
<motion.div
|
||||
animate="open"
|
||||
className={styles.queueDrawer}
|
||||
custom={windowBarStyle}
|
||||
exit="closed"
|
||||
id="drawer-queue"
|
||||
|
|
@ -140,7 +125,7 @@ export const RightSidebar = forwardRef(
|
|||
variants={queueDrawerVariants}
|
||||
>
|
||||
<DrawerPlayQueue />
|
||||
</QueueDrawer>
|
||||
</motion.div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
.queue-drawer-area {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 25px;
|
||||
z-index: 100;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 20px;
|
||||
height: 30px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.queue-drawer {
|
||||
background: var(--theme-colors-background);
|
||||
border: 3px solid var(--theme-generic-border-color);
|
||||
border-radius: var(--theme-radius-lg);
|
||||
}
|
||||
|
|
@ -1,33 +1,16 @@
|
|||
import { useDisclosure, useTimeout } from '@mantine/hooks';
|
||||
import { AnimatePresence, motion, Variants } from 'framer-motion';
|
||||
import { AnimatePresence, motion, Variants } from 'motion/react';
|
||||
import { useCallback } from 'react';
|
||||
import { TbArrowBarLeft } from 'react-icons/tb';
|
||||
import { useLocation } from 'react-router';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import styles from './side-drawer-queue.module.css';
|
||||
|
||||
import { DrawerPlayQueue } from '/@/renderer/features/now-playing';
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { useAppStore, useSidebarStore } from '/@/renderer/store';
|
||||
import { Icon } from '/@/shared/components/icon/icon';
|
||||
import { Platform } from '/@/shared/types/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;
|
||||
`;
|
||||
|
||||
const QueueDrawer = styled(motion.div)`
|
||||
background: var(--main-bg);
|
||||
border: 3px solid var(--generic-border-color);
|
||||
border-radius: 10px;
|
||||
`;
|
||||
|
||||
const queueDrawerVariants: Variants = {
|
||||
closed: (windowBarStyle) => ({
|
||||
height:
|
||||
|
|
@ -98,45 +81,48 @@ export const SideDrawerQueue = () => {
|
|||
!rightExpanded && !drawer && location.pathname !== AppRoute.NOW_PLAYING;
|
||||
|
||||
return (
|
||||
<>
|
||||
<AnimatePresence
|
||||
initial={false}
|
||||
mode="wait"
|
||||
>
|
||||
{isQueueDrawerButtonVisible && (
|
||||
<QueueDrawerArea
|
||||
animate="visible"
|
||||
exit="hidden"
|
||||
initial="hidden"
|
||||
key="queue-drawer-button"
|
||||
onMouseEnter={handleEnterDrawerButton}
|
||||
onMouseLeave={handleLeaveDrawerButton}
|
||||
variants={queueDrawerButtonVariants}
|
||||
whileHover={{ opacity: 1, scale: 2, transition: { duration: 0.5 } }}
|
||||
>
|
||||
<TbArrowBarLeft size={12} />
|
||||
</QueueDrawerArea>
|
||||
)}
|
||||
<AnimatePresence
|
||||
initial={false}
|
||||
mode="wait"
|
||||
>
|
||||
{isQueueDrawerButtonVisible && (
|
||||
<motion.div
|
||||
animate="visible"
|
||||
className={styles.queueDrawerArea}
|
||||
exit="hidden"
|
||||
initial="hidden"
|
||||
key="queue-drawer-button"
|
||||
onMouseEnter={handleEnterDrawerButton}
|
||||
onMouseLeave={handleLeaveDrawerButton}
|
||||
variants={queueDrawerButtonVariants}
|
||||
whileHover={{ opacity: 1, scale: 2, transition: { duration: 0.5 } }}
|
||||
>
|
||||
<Icon
|
||||
icon="arrowLeftToLine"
|
||||
size="lg"
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{drawer && (
|
||||
<QueueDrawer
|
||||
animate="open"
|
||||
exit="closed"
|
||||
initial="closed"
|
||||
key="queue-drawer"
|
||||
onMouseLeave={() => {
|
||||
// The drawer will close due to the delay when setting isReorderingQueue
|
||||
setTimeout(() => {
|
||||
if (useAppStore.getState().isReorderingQueue) return;
|
||||
drawerHandler.close();
|
||||
}, 50);
|
||||
}}
|
||||
variants={queueDrawerVariants}
|
||||
>
|
||||
<DrawerPlayQueue />
|
||||
</QueueDrawer>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</>
|
||||
{drawer && (
|
||||
<motion.div
|
||||
animate="open"
|
||||
className={styles.queueDrawer}
|
||||
exit="closed"
|
||||
initial="closed"
|
||||
key="queue-drawer"
|
||||
onMouseLeave={() => {
|
||||
// The drawer will close due to the delay when setting isReorderingQueue
|
||||
setTimeout(() => {
|
||||
if (useAppStore.getState().isReorderingQueue) return;
|
||||
drawerHandler.close();
|
||||
}, 50);
|
||||
}}
|
||||
variants={queueDrawerVariants}
|
||||
>
|
||||
<DrawerPlayQueue />
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
export * from './auth-layout';
|
||||
export * from './default-layout';
|
||||
91
src/renderer/layouts/window-bar.module.css
Normal file
91
src/renderer/layouts/window-bar.module.css
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
.windows-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100vw;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
.windows-button-group {
|
||||
display: flex;
|
||||
width: 130px;
|
||||
height: 100%;
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.windows-button {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
-webkit-app-region: no-drag;
|
||||
width: 50px;
|
||||
height: 30px;
|
||||
|
||||
img {
|
||||
width: 35%;
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgb(125 125 125 / 30%);
|
||||
}
|
||||
}
|
||||
|
||||
.windows-button.exit {
|
||||
&:hover {
|
||||
background: var(--theme-colors-state-error);
|
||||
}
|
||||
}
|
||||
|
||||
.player-status-container {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
max-width: 45vw;
|
||||
padding-left: 1rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.macos-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100vw;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
.macos-button-group {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 0.5rem;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 20px);
|
||||
height: 100%;
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.macos-button {
|
||||
grid-row: 1 / span 1;
|
||||
grid-column: 1;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
user-select: none;
|
||||
|
||||
img {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.macos-button.min-button {
|
||||
grid-column: 2;
|
||||
}
|
||||
|
||||
.macos-button.max-button,
|
||||
.macos-button.restore-button {
|
||||
grid-column: 3;
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import clsx from 'clsx';
|
||||
import isElectron from 'is-electron';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { RiCheckboxBlankLine, RiCloseLine, RiSubtractLine } from 'react-icons/ri';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import appIcon from '../../../assets/icons/32x32.png';
|
||||
import macCloseHover from './assets/close-mac-hover.png';
|
||||
|
|
@ -10,59 +10,15 @@ import macMaxHover from './assets/max-mac-hover.png';
|
|||
import macMax from './assets/max-mac.png';
|
||||
import macMinHover from './assets/min-mac-hover.png';
|
||||
import macMin from './assets/min-mac.png';
|
||||
import styles from './window-bar.module.css';
|
||||
|
||||
import { useCurrentStatus, useQueueStatus } from '/@/renderer/store';
|
||||
import { useWindowSettings } from '/@/renderer/store/settings.store';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { Platform, PlayerStatus } from '/@/shared/types/types';
|
||||
|
||||
const localSettings = isElectron() ? window.api.localSettings : null;
|
||||
|
||||
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;
|
||||
`;
|
||||
|
||||
const WindowsButtonGroup = styled.div`
|
||||
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;
|
||||
|
||||
img {
|
||||
width: 35%;
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
&: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;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
`;
|
||||
|
||||
const browser = isElectron() ? window.api.browser : null;
|
||||
const close = () => browser?.exit();
|
||||
const minimize = () => browser?.minimize();
|
||||
|
|
@ -82,82 +38,43 @@ const WindowsControls = ({ controls, title }: WindowBarControlsProps) => {
|
|||
const { handleClose, handleMaximize, handleMinimize } = controls;
|
||||
|
||||
return (
|
||||
<WindowsContainer>
|
||||
<PlayerStatusContainer>
|
||||
<div className={styles.windowsContainer}>
|
||||
<div className={styles.playerStatusContainer}>
|
||||
<img
|
||||
alt=""
|
||||
height={18}
|
||||
src={appIcon}
|
||||
width={18}
|
||||
/>
|
||||
{title}
|
||||
</PlayerStatusContainer>
|
||||
<WindowsButtonGroup>
|
||||
<WindowsButton
|
||||
<Text>{title}</Text>
|
||||
</div>
|
||||
<div className={styles.windowsButtonGroup}>
|
||||
<div
|
||||
className={styles.windowsButton}
|
||||
onClick={handleMinimize}
|
||||
role="button"
|
||||
>
|
||||
<RiSubtractLine size={19} />
|
||||
</WindowsButton>
|
||||
<WindowsButton
|
||||
</div>
|
||||
<div
|
||||
className={styles.windowsButton}
|
||||
onClick={handleMaximize}
|
||||
role="button"
|
||||
>
|
||||
<RiCheckboxBlankLine size={13} />
|
||||
</WindowsButton>
|
||||
<WindowsButton
|
||||
$exit
|
||||
</div>
|
||||
<div
|
||||
className={clsx(styles.windowsButton, styles.exit)}
|
||||
onClick={handleClose}
|
||||
role="button"
|
||||
>
|
||||
<RiCloseLine size={19} />
|
||||
</WindowsButton>
|
||||
</WindowsButtonGroup>
|
||||
</WindowsContainer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
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);
|
||||
`;
|
||||
|
||||
const MacOsButtonGroup = styled.div`
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 0.5rem;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 20px);
|
||||
height: 100%;
|
||||
|
||||
-webkit-app-region: no-drag;
|
||||
`;
|
||||
|
||||
export const MacOsButton = styled.div<{
|
||||
$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;
|
||||
|
||||
img {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
`;
|
||||
|
||||
const MacOsControls = ({ controls, title }: WindowBarControlsProps) => {
|
||||
const { handleClose, handleMaximize, handleMinimize } = controls;
|
||||
|
||||
|
|
@ -166,11 +83,10 @@ const MacOsControls = ({ controls, title }: WindowBarControlsProps) => {
|
|||
const [hoverClose, setHoverClose] = useState(false);
|
||||
|
||||
return (
|
||||
<MacOsContainer>
|
||||
<MacOsButtonGroup>
|
||||
<MacOsButton
|
||||
$minButton
|
||||
className="button"
|
||||
<div className={styles.macosContainer}>
|
||||
<div className={styles.macosButtonGroup}>
|
||||
<div
|
||||
className={clsx(styles.macosButton, styles.minButton)}
|
||||
id="min-button"
|
||||
onClick={handleMinimize}
|
||||
onMouseLeave={() => setHoverMin(false)}
|
||||
|
|
@ -182,10 +98,9 @@ const MacOsControls = ({ controls, title }: WindowBarControlsProps) => {
|
|||
draggable="false"
|
||||
src={hoverMin ? macMinHover : macMin}
|
||||
/>
|
||||
</MacOsButton>
|
||||
<MacOsButton
|
||||
$maxButton
|
||||
className="button"
|
||||
</div>
|
||||
<div
|
||||
className={clsx(styles.macosButton, styles.maxButton)}
|
||||
id="max-button"
|
||||
onClick={handleMaximize}
|
||||
onMouseLeave={() => setHoverMax(false)}
|
||||
|
|
@ -197,9 +112,9 @@ const MacOsControls = ({ controls, title }: WindowBarControlsProps) => {
|
|||
draggable="false"
|
||||
src={hoverMax ? macMaxHover : macMax}
|
||||
/>
|
||||
</MacOsButton>
|
||||
<MacOsButton
|
||||
className="button"
|
||||
</div>
|
||||
<div
|
||||
className={clsx(styles.macosButton)}
|
||||
id="close-button"
|
||||
onClick={handleClose}
|
||||
onMouseLeave={() => setHoverClose(false)}
|
||||
|
|
@ -211,10 +126,12 @@ const MacOsControls = ({ controls, title }: WindowBarControlsProps) => {
|
|||
draggable="false"
|
||||
src={hoverClose ? macCloseHover : macClose}
|
||||
/>
|
||||
</MacOsButton>
|
||||
</MacOsButtonGroup>
|
||||
<PlayerStatusContainer>{title}</PlayerStatusContainer>
|
||||
</MacOsContainer>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.playerStatusContainer}>
|
||||
<Text>{title}</Text>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue