Support dynamic page headers
This commit is contained in:
parent
3d8ba2e808
commit
65465d6cae
3 changed files with 97 additions and 13 deletions
|
@ -1,26 +1,27 @@
|
||||||
import { Flex, FlexProps } from '@mantine/core';
|
import { Flex, FlexProps } from '@mantine/core';
|
||||||
import { motion } from 'framer-motion';
|
import { AnimatePresence, motion, Variants } from 'framer-motion';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { useShouldPadTitlebar } from '/@/renderer/hooks';
|
import { useShouldPadTitlebar } from '/@/renderer/hooks';
|
||||||
|
|
||||||
const Container = styled(motion(Flex))<{ $isHidden?: boolean; height?: string; position?: string }>`
|
const Container = styled(motion(Flex))<{
|
||||||
|
height?: string;
|
||||||
|
position?: string;
|
||||||
|
}>`
|
||||||
position: ${(props) => props.position || 'relative'};
|
position: ${(props) => props.position || 'relative'};
|
||||||
z-index: 2000;
|
z-index: 2000;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: ${(props) => props.height || '60px'};
|
height: ${(props) => props.height || '60px'};
|
||||||
opacity: ${(props) => (props.$isHidden ? 0 : 1)};
|
|
||||||
transition: opacity 0.3s ease-in-out;
|
|
||||||
user-select: ${(props) => (props.$isHidden ? 'none' : 'auto')};
|
|
||||||
pointer-events: ${(props) => (props.$isHidden ? 'none' : 'auto')};
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Header = styled(motion.div)<{ $padRight?: boolean }>`
|
const Header = styled(motion.div)<{ $isHidden?: boolean; $padRight?: boolean }>`
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 15;
|
z-index: 15;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin-right: ${(props) => props.$padRight && '170px'};
|
margin-right: ${(props) => props.$padRight && '170px'};
|
||||||
|
user-select: ${(props) => (props.$isHidden ? 'none' : 'auto')};
|
||||||
|
pointer-events: ${(props) => (props.$isHidden ? 'none' : 'auto')};
|
||||||
-webkit-app-region: drag;
|
-webkit-app-region: drag;
|
||||||
|
|
||||||
button {
|
button {
|
||||||
|
@ -45,13 +46,13 @@ const BackgroundImageOverlay = styled.div`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 2;
|
z-index: 10;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: rgba(0, 0, 0, 30%), var(--background-noise);
|
background: linear-gradient(rgba(0, 0, 0, 50%), rgba(0, 0, 0, 50%));
|
||||||
`;
|
`;
|
||||||
|
|
||||||
interface PageHeaderProps
|
export interface PageHeaderProps
|
||||||
extends Omit<FlexProps, 'onAnimationStart' | 'onDragStart' | 'onDragEnd' | 'onDrag'> {
|
extends Omit<FlexProps, 'onAnimationStart' | 'onDragStart' | 'onDragEnd' | 'onDrag'> {
|
||||||
backgroundColor?: string;
|
backgroundColor?: string;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
@ -60,6 +61,17 @@ interface PageHeaderProps
|
||||||
position?: string;
|
position?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TitleWrapper = styled(motion.div)`
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const variants: Variants = {
|
||||||
|
animate: { opacity: 1 },
|
||||||
|
exit: { opacity: 0 },
|
||||||
|
initial: { opacity: 0 },
|
||||||
|
};
|
||||||
|
|
||||||
export const PageHeader = ({
|
export const PageHeader = ({
|
||||||
position,
|
position,
|
||||||
height,
|
height,
|
||||||
|
@ -74,15 +86,30 @@ export const PageHeader = ({
|
||||||
return (
|
return (
|
||||||
<Container
|
<Container
|
||||||
ref={ref}
|
ref={ref}
|
||||||
$isHidden={isHidden}
|
|
||||||
height={height}
|
height={height}
|
||||||
position={position}
|
position={position}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<Header $padRight={padRight}>{!isHidden && <>{children}</>}</Header>
|
<Header
|
||||||
|
$isHidden={isHidden}
|
||||||
|
$padRight={padRight}
|
||||||
|
>
|
||||||
|
<AnimatePresence>
|
||||||
|
{!isHidden && (
|
||||||
|
<TitleWrapper
|
||||||
|
animate="animate"
|
||||||
|
exit="exit"
|
||||||
|
initial="initial"
|
||||||
|
variants={variants}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</TitleWrapper>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</Header>
|
||||||
{backgroundColor && (
|
{backgroundColor && (
|
||||||
<>
|
<>
|
||||||
<BackgroundImage background={'var(--titlebar-bg)' || ''} />
|
<BackgroundImage background={backgroundColor || 'var(--titlebar-bg)'} />
|
||||||
<BackgroundImageOverlay />
|
<BackgroundImageOverlay />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
import { Group } from '@mantine/core';
|
||||||
|
import { TextTitle } from '/@/renderer/components';
|
||||||
|
import { PlayButton as PlayBtn } from '/@/renderer/features/shared/components/play-button';
|
||||||
|
|
||||||
|
interface LibraryHeaderBarProps {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LibraryHeaderBar = ({ children }: LibraryHeaderBarProps) => {
|
||||||
|
return (
|
||||||
|
<Group
|
||||||
|
noWrap
|
||||||
|
align="center"
|
||||||
|
h="100%"
|
||||||
|
px="1rem"
|
||||||
|
spacing="xl"
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Group>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface TitleProps {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Title = ({ children }: TitleProps) => {
|
||||||
|
return (
|
||||||
|
<TextTitle
|
||||||
|
fw="bold"
|
||||||
|
order={2}
|
||||||
|
overflow="hidden"
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</TextTitle>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface PlayButtonProps {
|
||||||
|
onClick: () => void;
|
||||||
|
size?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PlayButton = ({ size, onClick }: PlayButtonProps) => {
|
||||||
|
return (
|
||||||
|
<PlayBtn
|
||||||
|
h={size || 45}
|
||||||
|
w={size || 45}
|
||||||
|
onClick={onClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
LibraryHeaderBar.Title = Title;
|
||||||
|
LibraryHeaderBar.PlayButton = PlayButton;
|
|
@ -3,3 +3,4 @@ export * from './queries/music-folders-query';
|
||||||
export * from './components/play-button';
|
export * from './components/play-button';
|
||||||
export * from './utils';
|
export * from './utils';
|
||||||
export * from './components/library-header';
|
export * from './components/library-header';
|
||||||
|
export * from './components/library-header-bar';
|
||||||
|
|
Reference in a new issue