Support dynamic page headers

This commit is contained in:
jeffvli 2023-01-02 17:03:33 -08:00
parent 3d8ba2e808
commit 65465d6cae
3 changed files with 97 additions and 13 deletions

View file

@ -1,26 +1,27 @@
import { Flex, FlexProps } from '@mantine/core';
import { motion } from 'framer-motion';
import { AnimatePresence, motion, Variants } from 'framer-motion';
import { useRef } from 'react';
import styled from 'styled-components';
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'};
z-index: 2000;
width: 100%;
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;
z-index: 15;
width: 100%;
height: 100%;
margin-right: ${(props) => props.$padRight && '170px'};
user-select: ${(props) => (props.$isHidden ? 'none' : 'auto')};
pointer-events: ${(props) => (props.$isHidden ? 'none' : 'auto')};
-webkit-app-region: drag;
button {
@ -45,13 +46,13 @@ const BackgroundImageOverlay = styled.div`
position: absolute;
top: 0;
left: 0;
z-index: 2;
z-index: 10;
width: 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'> {
backgroundColor?: string;
children?: React.ReactNode;
@ -60,6 +61,17 @@ interface PageHeaderProps
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 = ({
position,
height,
@ -74,15 +86,30 @@ export const PageHeader = ({
return (
<Container
ref={ref}
$isHidden={isHidden}
height={height}
position={position}
{...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 && (
<>
<BackgroundImage background={'var(--titlebar-bg)' || ''} />
<BackgroundImage background={backgroundColor || 'var(--titlebar-bg)'} />
<BackgroundImageOverlay />
</>
)}

View file

@ -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;

View file

@ -3,3 +3,4 @@ export * from './queries/music-folders-query';
export * from './components/play-button';
export * from './utils';
export * from './components/library-header';
export * from './components/library-header-bar';