diff --git a/src/renderer/features/shared/components/item-image-placeholder.module.scss b/src/renderer/features/shared/components/item-image-placeholder.module.scss new file mode 100644 index 00000000..afca7b67 --- /dev/null +++ b/src/renderer/features/shared/components/item-image-placeholder.module.scss @@ -0,0 +1,12 @@ +.image-placeholder { + width: 100%; + height: 100%; + background-color: var(--placeholder-bg); + border-radius: var(--card-default-radius); + + svg { + width: 35px; + height: 35px; + color: var(--placeholder-fg); + } +} diff --git a/src/renderer/features/shared/components/item-image-placeholder.tsx b/src/renderer/features/shared/components/item-image-placeholder.tsx new file mode 100644 index 00000000..1944eae3 --- /dev/null +++ b/src/renderer/features/shared/components/item-image-placeholder.tsx @@ -0,0 +1,32 @@ +import { Center } from '@mantine/core'; +import { memo } from 'react'; +import { RiAlbumFill, RiPlayListFill, RiUserVoiceFill } from 'react-icons/ri'; +import styles from './item-image-placeholder.module.scss'; +import { LibraryItem } from '/@/renderer/api/types'; + +interface ItemImagePlaceholderProps { + itemType?: LibraryItem; +} + +const Image = memo(function Image(props: ItemImagePlaceholderProps) { + switch (props.itemType) { + case LibraryItem.ALBUM: + return ; + case LibraryItem.ARTIST: + return ; + case LibraryItem.ALBUM_ARTIST: + return ; + case LibraryItem.PLAYLIST: + return ; + default: + return ; + } +}); + +export const ItemImagePlaceholder = ({ itemType }: ItemImagePlaceholderProps) => { + return ( +
+ +
+ ); +}; diff --git a/src/renderer/features/shared/components/library-header.module.scss b/src/renderer/features/shared/components/library-header.module.scss new file mode 100644 index 00000000..1c9f5f9a --- /dev/null +++ b/src/renderer/features/shared/components/library-header.module.scss @@ -0,0 +1,126 @@ +.library-header { + position: relative; + display: grid; + grid-template-areas: 'image info'; + grid-template-rows: 100%; + grid-template-columns: 175px minmax(0, 1fr); + gap: 1rem; + width: 100%; + max-width: 100%; + height: 30vh; + min-height: 340px; + max-height: 500px; + padding: 5rem 2rem 2rem; + + @container (min-width: 600px) { + grid-template-columns: 175px minmax(0, 1fr); + + h1 { + font-size: 3rem; + } + + .image { + img { + width: 175px !important; + height: 175px; + } + } + } + + @container (min-width: 600px) { + grid-template-columns: 200px minmax(0, 1fr); + + h1 { + font-size: 4.5rem; + } + + .image { + img { + width: 200px !important; + height: 200px; + } + } + } + + @container (min-width: 768px) { + grid-template-columns: 225px minmax(0, 1fr); + + h1 { + font-size: 5rem; + } + + .image { + img { + width: 225px !important; + height: 225px; + } + } + } + + @container (min-width: 1200px) { + grid-template-columns: 250px minmax(0, 1fr); + + h1 { + font-size: 5.5rem; + } + + .image { + img { + width: 250px !important; + height: 250px; + } + } + } +} + +.image-section { + z-index: 15; + display: flex; + grid-area: image; + align-items: flex-end; + justify-content: center; + height: 100%; + filter: drop-shadow(0 0 8px rgb(0, 0, 0, 50%)); +} + +.metadata-section { + z-index: 15; + display: flex; + flex-direction: column; + grid-area: info; + justify-content: flex-end; + width: 100%; +} + +.image { + img { + object-fit: cover; + } +} + +.background { + position: absolute; + top: 0; + z-index: 0; + width: 100%; + height: 100%; + opacity: 0.9; +} + +.background-overlay { + position: absolute; + top: 0; + left: 0; + z-index: 0; + width: 100%; + height: 100%; + background: var(--bg-header-overlay); +} + +.title { + overflow: hidden; + color: var(--main-fg); + line-height: 1.15; + white-space: nowrap; + text-overflow: ellipsis; +} diff --git a/src/renderer/features/shared/components/library-header.tsx b/src/renderer/features/shared/components/library-header.tsx index bfb9941e..3fc6a961 100644 --- a/src/renderer/features/shared/components/library-header.tsx +++ b/src/renderer/features/shared/components/library-header.tsx @@ -1,74 +1,11 @@ +import { Group } from '@mantine/core'; import { forwardRef, ReactNode, Ref } from 'react'; -import { Center, Group } from '@mantine/core'; -import { useMergedRef } from '@mantine/hooks'; -import { RiAlbumFill } from 'react-icons/ri'; import { Link } from 'react-router-dom'; import { SimpleImg } from 'react-simple-img'; -import styled from 'styled-components'; +import styles from './library-header.module.scss'; import { LibraryItem } from '/@/renderer/api/types'; -import { Text, TextTitle } from '/@/renderer/components'; -import { useContainerQuery } from '/@/renderer/hooks'; - -const HeaderContainer = styled.div<{ imageSize: number }>` - position: relative; - display: grid; - grid-auto-columns: 1fr; - grid-template-areas: 'image info'; - grid-template-rows: 1fr; - grid-template-columns: ${(props) => props.imageSize + 25}px minmax(0, 1fr); - gap: 0.5rem; - width: 100%; - max-width: 100%; - height: 30vh; - min-height: 340px; - max-height: 500px; - padding: 5rem 2rem 2rem; -`; - -const CoverImageWrapper = styled.div` - z-index: 15; - display: flex; - grid-area: image; - align-items: flex-end; - justify-content: center; - height: 100%; - filter: drop-shadow(0 0 8px rgb(0, 0, 0, 50%)); -`; - -const MetadataWrapper = styled.div` - z-index: 15; - display: flex; - flex-direction: column; - grid-area: info; - justify-content: flex-end; - width: 100%; -`; - -const StyledImage = styled(SimpleImg)` - img { - object-fit: cover; - } -`; - -const BackgroundImage = styled.div<{ background: string }>` - position: absolute; - top: 0; - z-index: 0; - width: 100%; - height: 100%; - background: ${(props) => props.background}; - opacity: 0.9; -`; - -const BackgroundImageOverlay = styled.div` - position: absolute; - top: 0; - left: 0; - z-index: 0; - width: 100%; - height: 100%; - background: var(--bg-header-overlay); -`; +import { Text } from '/@/renderer/components'; +import { ItemImagePlaceholder } from '/@/renderer/features/shared/components/item-image-placeholder'; interface LibraryHeaderProps { background: string; @@ -84,53 +21,30 @@ export const LibraryHeader = forwardRef( { imageUrl, imagePlaceholderUrl, background, title, item, children }: LibraryHeaderProps, ref: Ref, ) => { - const cq = useContainerQuery(); - const mergedRef = useMergedRef(ref, cq.ref); - const titleSize = cq.isXl - ? '6rem' - : cq.isLg - ? '5.5rem' - : cq.isMd - ? '5rem' - : cq.isSm - ? '4.5rem' - : '3rem'; - - const imageSize = cq.isLg ? 250 : cq.isMd ? 225 : cq.isSm ? 200 : 175; - return ( - - - - +
+
+
{imageUrl ? ( - ) : ( -
- -
+ )} - - +
+
- - {title} - +

{title}

{children} - - +
+
); }, );