mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-08 04:50:12 +02:00
Migrate to Mantine v8 and Design Changes (#961)
* mantine v8 migration * various design changes and improvements
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
.carousel {
|
||||
position: relative;
|
||||
height: 35vh;
|
||||
min-height: 250px;
|
||||
max-height: 300px;
|
||||
padding: var(--theme-spacing-md);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-areas: 'image info';
|
||||
grid-template-rows: 1fr;
|
||||
grid-template-columns: 200px minmax(0, 1fr);
|
||||
grid-auto-columns: 1fr;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.image-column {
|
||||
z-index: 15;
|
||||
display: flex;
|
||||
grid-area: image;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.info-column {
|
||||
z-index: 15;
|
||||
display: flex;
|
||||
grid-area: info;
|
||||
align-items: flex-end;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
.background-image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 0;
|
||||
width: 150%;
|
||||
height: 150%;
|
||||
user-select: none;
|
||||
object-fit: var(--theme-image-fit);
|
||||
object-position: 0 30%;
|
||||
filter: blur(24px);
|
||||
}
|
||||
|
||||
.background-image-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(180deg, rgb(25 26 28 / 30%), var(--theme-colors-background));
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.title-wrapper {
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
+51
-136
@@ -1,99 +1,28 @@
|
||||
import type { Variants } from 'framer-motion';
|
||||
import type { Variants } from 'motion/react';
|
||||
import type { MouseEvent } from 'react';
|
||||
|
||||
import { Group, Image, Stack } from '@mantine/core';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { AnimatePresence, motion } from 'motion/react';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { RiArrowLeftSLine, RiArrowRightSLine } from 'react-icons/ri';
|
||||
import { generatePath, Link } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { Badge } from '/@/renderer/components/badge';
|
||||
import { Button } from '/@/renderer/components/button';
|
||||
import { TextTitle } from '/@/renderer/components/text-title';
|
||||
import styles from './feature-carousel.module.css';
|
||||
|
||||
import { usePlayQueueAdd } from '/@/renderer/features/player/hooks/use-playqueue-add';
|
||||
import { PlayButton } from '/@/renderer/features/shared';
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { usePlayButtonBehavior } from '/@/renderer/store';
|
||||
import { Badge } from '/@/shared/components/badge/badge';
|
||||
import { Button } from '/@/shared/components/button/button';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
import { Icon } from '/@/shared/components/icon/icon';
|
||||
import { Image } from '/@/shared/components/image/image';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { TextTitle } from '/@/shared/components/text-title/text-title';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { Album, LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
const Carousel = styled(motion.div)`
|
||||
position: relative;
|
||||
height: 35vh;
|
||||
min-height: 250px;
|
||||
padding: 2rem;
|
||||
overflow: hidden;
|
||||
background: linear-gradient(180deg, var(--main-bg), rgb(25 26 28 / 60%));
|
||||
border-radius: 1rem;
|
||||
`;
|
||||
|
||||
const Grid = styled.div`
|
||||
display: grid;
|
||||
grid-template-areas: 'image info';
|
||||
grid-template-rows: 1fr;
|
||||
grid-template-columns: 200px minmax(0, 1fr);
|
||||
grid-auto-columns: 1fr;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
const ImageColumn = styled.div`
|
||||
z-index: 15;
|
||||
display: flex;
|
||||
grid-area: image;
|
||||
align-items: flex-end;
|
||||
`;
|
||||
|
||||
const InfoColumn = styled.div`
|
||||
z-index: 15;
|
||||
display: flex;
|
||||
grid-area: info;
|
||||
align-items: flex-end;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding-left: 1rem;
|
||||
`;
|
||||
|
||||
const BackgroundImage = styled.img`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 0;
|
||||
width: 150%;
|
||||
height: 150%;
|
||||
user-select: none;
|
||||
object-fit: var(--image-fit);
|
||||
object-position: 0 30%;
|
||||
filter: blur(24px);
|
||||
`;
|
||||
|
||||
const BackgroundImageOverlay = styled.div`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(180deg, rgb(25 26 28 / 30%), var(--main-bg));
|
||||
`;
|
||||
|
||||
const Wrapper = styled(Link)`
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
const TitleWrapper = styled.div`
|
||||
/* stylelint-disable-next-line value-no-vendor-prefix */
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
const variants: Variants = {
|
||||
animate: {
|
||||
opacity: 1,
|
||||
@@ -144,7 +73,8 @@ export const FeatureCarousel = ({ data }: FeatureCarouselProps) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Wrapper
|
||||
<Link
|
||||
className={styles.wrapper}
|
||||
to={generatePath(AppRoute.LIBRARY_ALBUMS_DETAIL, { albumId: currentItem?.id || '' })}
|
||||
>
|
||||
<AnimatePresence
|
||||
@@ -153,73 +83,61 @@ export const FeatureCarousel = ({ data }: FeatureCarouselProps) => {
|
||||
mode="popLayout"
|
||||
>
|
||||
{data && (
|
||||
<Carousel
|
||||
<motion.div
|
||||
animate="animate"
|
||||
className={styles.carousel}
|
||||
custom={direction}
|
||||
exit="exit"
|
||||
initial="initial"
|
||||
key={`image-${itemIndex}`}
|
||||
variants={variants}
|
||||
>
|
||||
<Grid>
|
||||
<ImageColumn>
|
||||
<div className={styles.grid}>
|
||||
<div className={styles.imageColumn}>
|
||||
<Image
|
||||
height={225}
|
||||
placeholder="var(--card-default-bg)"
|
||||
radius="md"
|
||||
src={data[itemIndex]?.imageUrl}
|
||||
sx={{ objectFit: 'cover' }}
|
||||
src={data[itemIndex]?.imageUrl || ''}
|
||||
width={225}
|
||||
/>
|
||||
</ImageColumn>
|
||||
<InfoColumn>
|
||||
</div>
|
||||
<div className={styles.infoColumn}>
|
||||
<Stack
|
||||
spacing="md"
|
||||
sx={{ width: '100%' }}
|
||||
gap="md"
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
<TitleWrapper>
|
||||
<div className={styles.titleWrapper}>
|
||||
<TextTitle
|
||||
lh="3.5rem"
|
||||
fw={900}
|
||||
lineClamp={2}
|
||||
order={1}
|
||||
overflow="hidden"
|
||||
sx={{ fontSize: '3.5rem' }}
|
||||
weight={900}
|
||||
>
|
||||
{currentItem?.name}
|
||||
</TextTitle>
|
||||
</TitleWrapper>
|
||||
<TitleWrapper>
|
||||
</div>
|
||||
<div className={styles.titleWrapper}>
|
||||
{currentItem?.albumArtists.slice(0, 1).map((artist) => (
|
||||
<TextTitle
|
||||
<Text
|
||||
fw={600}
|
||||
key={`carousel-artist-${artist.id}`}
|
||||
order={2}
|
||||
weight={600}
|
||||
>
|
||||
{artist.name}
|
||||
</TextTitle>
|
||||
</Text>
|
||||
))}
|
||||
</TitleWrapper>
|
||||
</div>
|
||||
<Group>
|
||||
{currentItem?.genres?.slice(0, 1).map((genre) => (
|
||||
<Badge
|
||||
key={`carousel-genre-${genre.id}`}
|
||||
size="lg"
|
||||
variant="default"
|
||||
>
|
||||
{genre.name}
|
||||
</Badge>
|
||||
))}
|
||||
<Badge size="lg">{currentItem?.releaseYear}</Badge>
|
||||
{currentItem?.songCount !== null &&
|
||||
currentItem?.songCount !== undefined && (
|
||||
<Badge size="lg">
|
||||
{t('entity.trackWithCount', {
|
||||
count: currentItem?.songCount || 0,
|
||||
})}
|
||||
</Badge>
|
||||
)}
|
||||
<Badge variant="default">{currentItem?.releaseYear}</Badge>
|
||||
</Group>
|
||||
<Group position="apart">
|
||||
<Button
|
||||
<Group justify="space-between">
|
||||
<PlayButton
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@@ -233,8 +151,6 @@ export const FeatureCarousel = ({ data }: FeatureCarouselProps) => {
|
||||
playType,
|
||||
});
|
||||
}}
|
||||
size="lg"
|
||||
style={{ borderRadius: '5rem' }}
|
||||
variant="outline"
|
||||
>
|
||||
{t(
|
||||
@@ -245,37 +161,36 @@ export const FeatureCarousel = ({ data }: FeatureCarouselProps) => {
|
||||
: 'player.addLast',
|
||||
{ postProcess: 'titleCase' },
|
||||
)}
|
||||
</Button>
|
||||
<Group spacing="sm">
|
||||
</PlayButton>
|
||||
<Group gap="sm">
|
||||
<Button
|
||||
onClick={handlePrevious}
|
||||
radius="lg"
|
||||
size="sm"
|
||||
variant="outline"
|
||||
variant="subtle"
|
||||
>
|
||||
<RiArrowLeftSLine size="2rem" />
|
||||
<Icon icon="arrowLeftS" />
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleNext}
|
||||
radius="lg"
|
||||
size="sm"
|
||||
variant="outline"
|
||||
variant="subtle"
|
||||
>
|
||||
<RiArrowRightSLine size="2rem" />
|
||||
<Icon icon="arrowRightS" />
|
||||
</Button>
|
||||
</Group>
|
||||
</Group>
|
||||
</Stack>
|
||||
</InfoColumn>
|
||||
</Grid>
|
||||
<BackgroundImage
|
||||
</div>
|
||||
</div>
|
||||
<Image
|
||||
className={styles.backgroundImage}
|
||||
draggable="false"
|
||||
src={currentItem?.imageUrl || undefined}
|
||||
src={currentItem?.imageUrl || ''}
|
||||
/>
|
||||
<BackgroundImageOverlay />
|
||||
</Carousel>
|
||||
<div className={styles.backgroundImageOverlay} />
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</Wrapper>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user