adjust styles on fullscreen player image section

- fix image transition
- fix image aspect ratio
- adjust text sizes and shadow
This commit is contained in:
jeffvli 2025-06-25 20:40:45 -07:00
parent 0afbe4c0a2
commit 64866c59bd
3 changed files with 65 additions and 35 deletions

View file

@ -2,7 +2,6 @@
position: absolute; position: absolute;
max-width: 100%; max-width: 100%;
height: 100%; height: 100%;
object-fit: var(--theme-image-fit);
object-position: 50% 100%; object-position: 50% 100%;
border-radius: 5px; border-radius: 5px;
filter: drop-shadow(0 0 5px rgb(0 0 0 / 40%)) drop-shadow(0 0 5px rgb(0 0 0 / 40%)); filter: drop-shadow(0 0 5px rgb(0 0 0 / 40%)) drop-shadow(0 0 5px rgb(0 0 0 / 40%));
@ -24,8 +23,13 @@
justify-content: center; justify-content: center;
padding: 1rem; padding: 1rem;
text-align: center; text-align: center;
cursor: default;
border-radius: 5px; border-radius: 5px;
a {
cursor: pointer;
}
h1 { h1 {
font-size: 3.5vh; font-size: 3.5vh;
} }

View file

@ -16,9 +16,7 @@ import { Center } from '/@/shared/components/center/center';
import { Flex } from '/@/shared/components/flex/flex'; import { Flex } from '/@/shared/components/flex/flex';
import { Group } from '/@/shared/components/group/group'; import { Group } from '/@/shared/components/group/group';
import { Icon } from '/@/shared/components/icon/icon'; import { Icon } from '/@/shared/components/icon/icon';
import { Image } from '/@/shared/components/image/image';
import { Stack } from '/@/shared/components/stack/stack'; import { Stack } from '/@/shared/components/stack/stack';
import { TextTitle } from '/@/shared/components/text-title/text-title';
import { Text } from '/@/shared/components/text/text'; import { Text } from '/@/shared/components/text/text';
import { PlayerData, QueueSong } from '/@/shared/types/domain-types'; import { PlayerData, QueueSong } from '/@/shared/types/domain-types';
@ -52,9 +50,14 @@ const scaleImageUrl = (imageSize: number, url?: null | string) => {
.replace(/&height=\d+/, `&height=${imageSize}`); .replace(/&height=\d+/, `&height=${imageSize}`);
}; };
const MotionImage = motion.create(Image); const MotionImage = motion.img;
const ImageWithPlaceholder = ({
className,
...props
}: HTMLMotionProps<'img'> & { placeholder?: string }) => {
const nativeAspectRatio = useSettingsStore((store) => store.general.nativeAspectRatio);
const ImageWithPlaceholder = ({ ...props }: HTMLMotionProps<'img'> & { placeholder?: string }) => {
if (!props.src) { if (!props.src) {
return ( return (
<Center <Center
@ -76,7 +79,11 @@ const ImageWithPlaceholder = ({ ...props }: HTMLMotionProps<'img'> & { placehold
return ( return (
<MotionImage <MotionImage
className={styles.image} className={clsx(styles.image, className)}
style={{
objectFit: nativeAspectRatio ? 'contain' : 'cover',
width: nativeAspectRatio ? 'auto' : '100%',
}}
{...props} {...props}
/> />
); );
@ -201,40 +208,32 @@ export const FullScreenPlayerImage = () => {
</div> </div>
<Stack <Stack
className={styles.metadataContainer} className={styles.metadataContainer}
gap="xs" gap="2px"
maw="100%" maw="100%"
> >
<TextTitle <Text
fw={900} fw={900}
order={1} lh="1.2"
overflow="hidden" overflow="hidden"
size="4xl"
w="100%" w="100%"
> >
{currentSong?.name} {currentSong?.name}
</TextTitle> </Text>
<TextTitle <Text
component={Link} component={Link}
fw={600} fw={600}
isLink isLink
order={3}
overflow="hidden" overflow="hidden"
style={{ size="xl"
textShadow: 'var(--theme-fullscreen-player-text-shadow)',
}}
to={generatePath(AppRoute.LIBRARY_ALBUMS_DETAIL, { to={generatePath(AppRoute.LIBRARY_ALBUMS_DETAIL, {
albumId: currentSong?.albumId || '', albumId: currentSong?.albumId || '',
})} })}
w="100%" w="100%"
> >
{currentSong?.album}{' '} {currentSong?.album}
</TextTitle> </Text>
<TextTitle <Text key="fs-artists">
key="fs-artists"
order={3}
style={{
textShadow: 'var(--theme-fullscreen-player-text-shadow)',
}}
>
{currentSong?.artists?.map((artist, index) => ( {currentSong?.artists?.map((artist, index) => (
<Fragment key={`fs-artist-${artist.id}`}> <Fragment key={`fs-artist-${artist.id}`}>
{index > 0 && ( {index > 0 && (
@ -253,9 +252,6 @@ export const FullScreenPlayerImage = () => {
fw={600} fw={600}
isLink isLink
isMuted isMuted
style={{
textShadow: 'var(--theme-fullscreen-player-text-shadow)',
}}
to={generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL, { to={generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL, {
albumArtistId: artist.id, albumArtistId: artist.id,
})} })}
@ -264,7 +260,7 @@ export const FullScreenPlayerImage = () => {
</Text> </Text>
</Fragment> </Fragment>
))} ))}
</TextTitle> </Text>
<Group <Group
justify="center" justify="center"
mt="sm" mt="sm"

View file

@ -1,16 +1,18 @@
import type { ImgHTMLAttributes } from 'react';
import clsx from 'clsx'; import clsx from 'clsx';
import { motion, MotionConfigProps } from 'motion/react';
import { type ImgHTMLAttributes } from 'react';
import { Img } from 'react-image'; import { Img } from 'react-image';
import styles from './image.module.css'; import styles from './image.module.css';
import { animationProps } from '/@/shared/components/animations/animation-props';
import { Icon } from '/@/shared/components/icon/icon'; import { Icon } from '/@/shared/components/icon/icon';
import { Skeleton } from '/@/shared/components/skeleton/skeleton'; import { Skeleton } from '/@/shared/components/skeleton/skeleton';
interface ImageContainerProps { interface ImageContainerProps extends MotionConfigProps {
children: React.ReactNode; children: React.ReactNode;
className?: string; className?: string;
enableAnimation?: boolean;
} }
interface ImageLoaderProps { interface ImageLoaderProps {
@ -19,6 +21,8 @@ interface ImageLoaderProps {
interface ImageProps extends Omit<ImgHTMLAttributes<HTMLImageElement>, 'src'> { interface ImageProps extends Omit<ImgHTMLAttributes<HTMLImageElement>, 'src'> {
containerClassName?: string; containerClassName?: string;
enableAnimation?: boolean;
imageContainerProps?: Omit<ImageContainerProps, 'children'>;
includeLoader?: boolean; includeLoader?: boolean;
includeUnloader?: boolean; includeUnloader?: boolean;
src: string | string[] | undefined; src: string | string[] | undefined;
@ -32,6 +36,8 @@ interface ImageUnloaderProps {
export function Image({ export function Image({
className, className,
containerClassName, containerClassName,
enableAnimation,
imageContainerProps,
includeLoader = true, includeLoader = true,
includeUnloader = true, includeUnloader = true,
src, src,
@ -41,7 +47,13 @@ export function Image({
<Img <Img
className={clsx(styles.image, className)} className={clsx(styles.image, className)}
container={(children) => ( container={(children) => (
<ImageContainer className={containerClassName}>{children}</ImageContainer> <ImageContainer
className={containerClassName}
enableAnimation={enableAnimation}
{...imageContainerProps}
>
{children}
</ImageContainer>
)} )}
loader={ loader={
includeLoader ? ( includeLoader ? (
@ -50,7 +62,6 @@ export function Image({
</ImageContainer> </ImageContainer>
) : null ) : null
} }
loading="lazy"
src={src} src={src}
unloader={ unloader={
includeUnloader ? ( includeUnloader ? (
@ -66,8 +77,27 @@ export function Image({
return <ImageUnloader />; return <ImageUnloader />;
} }
function ImageContainer({ children, className }: ImageContainerProps) { function ImageContainer({ children, className, enableAnimation, ...props }: ImageContainerProps) {
return <div className={clsx(styles.imageContainer, className)}>{children}</div>; if (!enableAnimation) {
return (
<div
className={clsx(styles.imageContainer, className)}
{...props}
>
{children}
</div>
);
}
return (
<motion.div
className={clsx(styles.imageContainer, className)}
{...animationProps.fadeIn}
{...props}
>
{children}
</motion.div>
);
} }
function ImageLoader({ className }: ImageLoaderProps) { function ImageLoader({ className }: ImageLoaderProps) {