diff --git a/src/renderer/components/page-header/index.tsx b/src/renderer/components/page-header/index.tsx index 93cf1cb2..2db3b3a4 100644 --- a/src/renderer/components/page-header/index.tsx +++ b/src/renderer/components/page-header/index.tsx @@ -1,22 +1,26 @@ +import { Flex, FlexProps } from '@mantine/core'; import { motion } from 'framer-motion'; import { useEffect, useRef } from 'react'; import styled from 'styled-components'; import { useShouldPadTitlebar } from '/@/renderer/hooks'; -const Container = styled(motion.div)<{ $useOpacity?: boolean; height?: string; position?: string }>` - position: ${(props) => props.position}; - z-index: 100; +const Container = styled(motion(Flex))<{ $isHidden?: boolean; height?: string; position?: string }>` + position: ${(props) => props.position || 'relative'}; + z-index: 2000; width: 100%; height: ${(props) => props.height || '60px'}; - opacity: ${(props) => props.$useOpacity && 'var(--header-opacity)'}; + 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 }>` + position: relative; z-index: 15; + width: 100%; height: 100%; margin-right: ${(props) => props.$padRight && '170px'}; - padding: 1rem; -webkit-app-region: drag; button { @@ -28,40 +32,41 @@ const Header = styled(motion.div)<{ $padRight?: boolean }>` } `; -// const BackgroundImage = styled.div<{ background: string }>` -// position: absolute; -// top: 0; -// z-index: -1; -// width: 100%; -// height: 100%; -// background: ${(props) => props.background}; -// `; +const BackgroundImage = styled.div<{ background: string }>` + position: absolute; + top: 0; + z-index: 1; + width: 100%; + height: 100%; + background: ${(props) => props.background || 'var(--titlebar-bg)'}; +`; -// const BackgroundImageOverlay = styled.div` -// position: absolute; -// top: 0; -// left: 0; -// z-index: -1; -// width: 100%; -// height: 100%; -// /* background: linear-gradient(180deg, rgba(25, 26, 28, 0%), var(--main-bg)); */ -// /* background: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMDAiIGhlaWdodD0iMzAwIj48ZmlsdGVyIGlkPSJhIiB4PSIwIiB5PSIwIj48ZmVUdXJidWxlbmNlIHR5cGU9ImZyYWN0YWxOb2lzZSIgYmFzZUZyZXF1ZW5jeT0iLjc1IiBzdGl0Y2hUaWxlcz0ic3RpdGNoIi8+PGZlQ29sb3JNYXRyaXggdHlwZT0ic2F0dXJhdGUiIHZhbHVlcz0iMCIvPjwvZmlsdGVyPjxwYXRoIGZpbHRlcj0idXJsKCNhKSIgb3BhY2l0eT0iLjA1IiBkPSJNMCAwaDMwMHYzMDBIMHoiLz48L3N2Zz4='); */ -// `; +const BackgroundImageOverlay = styled.div` + position: absolute; + top: 0; + left: 0; + z-index: 2; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 30%), var(--background-noise); +`; -interface PageHeaderProps { +interface PageHeaderProps + extends Omit { backgroundColor?: string; children?: React.ReactNode; height?: string; + isHidden?: boolean; position?: string; - useOpacity?: boolean; } export const PageHeader = ({ position, height, backgroundColor, - useOpacity, + isHidden, children, + ...props }: PageHeaderProps) => { const ref = useRef(null); const padRight = useShouldPadTitlebar(); @@ -74,17 +79,18 @@ export const PageHeader = ({ return ( -
{children}
- {/* */} - {/* */} +
{!isHidden && <>{children}}
+ {backgroundColor && ( + <> + + + + )}
); }; diff --git a/src/renderer/features/albums/components/album-detail-header.tsx b/src/renderer/features/albums/components/album-detail-header.tsx index 1c966145..1c4a7592 100644 --- a/src/renderer/features/albums/components/album-detail-header.tsx +++ b/src/renderer/features/albums/components/album-detail-header.tsx @@ -1,5 +1,6 @@ import { Center, Group } from '@mantine/core'; -import { Fragment } from 'react'; +import { useMergedRef } from '@mantine/hooks'; +import { forwardRef, Fragment, Ref } from 'react'; import { RiAlbumFill } from 'react-icons/ri'; import { generatePath, useParams } from 'react-router'; import { Link } from 'react-router-dom'; @@ -64,119 +65,122 @@ const BackgroundImageOverlay = styled.div` z-index: 0; width: 100%; height: 100%; - background: linear-gradient(180deg, rgba(25, 26, 28, 5%), var(--main-bg)); + background: linear-gradient(180deg, rgba(25, 26, 28, 5%), var(--main-bg)), var(--background-noise); `; interface AlbumDetailHeaderProps { background: string; } -export const AlbumDetailHeader = ({ background }: AlbumDetailHeaderProps) => { - const { albumId } = useParams() as { albumId: string }; - const detailQuery = useAlbumDetail({ id: albumId }); - const cq = useContainerQuery(); +export const AlbumDetailHeader = forwardRef( + ({ background }: AlbumDetailHeaderProps, ref: Ref) => { + const { albumId } = useParams() as { albumId: string }; + const detailQuery = useAlbumDetail({ id: albumId }); + const cq = useContainerQuery(); + const mergedRef = useMergedRef(ref, cq.ref); - const titleSize = cq.isXl - ? '6rem' - : cq.isLg - ? '5.5rem' - : cq.isMd - ? '4.5rem' - : cq.isSm - ? '3.5rem' - : '2rem'; + const titleSize = cq.isXl + ? '6rem' + : cq.isLg + ? '5.5rem' + : cq.isMd + ? '4.5rem' + : cq.isSm + ? '3.5rem' + : '2rem'; - return ( - - - - - {detailQuery?.data?.imageUrl ? ( - - ) : ( -
+ + + + {detailQuery?.data?.imageUrl ? ( + + ) : ( +
+ +
+ )} +
+ + + + Album + + {detailQuery?.data?.releaseYear && ( + <> + + {detailQuery?.data?.releaseYear} + + )} + + + {detailQuery?.data?.name} + + - -
- )} -
- - - - Album - - {detailQuery?.data?.releaseYear && ( - <> - - {detailQuery?.data?.releaseYear} - - )} - - - {detailQuery?.data?.name} - - - {detailQuery?.data?.albumArtists.map((artist, index) => ( - - {index > 0 && ( + {detailQuery?.data?.albumArtists.map((artist, index) => ( + + {index > 0 && ( + + • + + )} - • + {artist.name} - )} - - {artist.name} - - - ))} - - -
- ); -}; + + ))} + + + + ); + }, +); diff --git a/src/renderer/features/albums/components/album-list-header.tsx b/src/renderer/features/albums/components/album-list-header.tsx index c6e09bd9..b069bad6 100644 --- a/src/renderer/features/albums/components/album-list-header.tsx +++ b/src/renderer/features/albums/components/album-list-header.tsx @@ -296,7 +296,7 @@ export const AlbumListHeader = ({ gridRef, tableRef }: AlbumListHeaderProps) => }; return ( - + { const tableRef = useRef(null); const { albumId } = useParams() as { albumId: string }; const detailQuery = useAlbumDetail({ id: albumId }); const background = useFastAverageColor(detailQuery.data?.imageUrl); + const padTop = useShouldPadTitlebar(); + + const containerRef = useRef(); + const { ref, entry } = useIntersection({ + root: containerRef.current, + threshold: 0, + }); return ( + > + + + + {detailQuery?.data?.name} + + + {background && ( <> - + )} diff --git a/src/renderer/features/artists/components/album-artist-list-header.tsx b/src/renderer/features/artists/components/album-artist-list-header.tsx index cd4486c1..e014d473 100644 --- a/src/renderer/features/artists/components/album-artist-list-header.tsx +++ b/src/renderer/features/artists/components/album-artist-list-header.tsx @@ -289,7 +289,7 @@ export const AlbumArtistListHeader = ({ gridRef, tableRef }: AlbumArtistListHead }; return ( - + { { const queueRef = useRef<{ grid: AgGridReactType } | null>(null); return ( - - - - - + <> + + + + + + + + + ); }; diff --git a/src/renderer/features/playlists/components/playlist-list-header.tsx b/src/renderer/features/playlists/components/playlist-list-header.tsx index 6bbf1618..c65f0bf4 100644 --- a/src/renderer/features/playlists/components/playlist-list-header.tsx +++ b/src/renderer/features/playlists/components/playlist-list-header.tsx @@ -189,7 +189,7 @@ export const PlaylistListHeader = ({ tableRef }: PlaylistListHeaderProps) => { }; return ( - + { }; return ( - +