import { createContext, useContext, useState, useCallback, useMemo } from 'react'; import { Group, Stack } from '@mantine/core'; import type { Variants } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion'; import { RiArrowLeftSLine, RiArrowRightSLine } from 'react-icons/ri'; import { Button } from '/@/renderer/components/button'; import { AppRoute } from '/@/renderer/router/routes'; import type { CardRow } from '/@/renderer/types'; import { LibraryItem, Play } from '/@/renderer/types'; import styled from 'styled-components'; import { AlbumCard } from '/@/renderer/components/card'; import { useHandlePlayQueueAdd } from '/@/renderer/features/player/hooks/use-handle-playqueue-add'; interface GridCarouselProps { cardRows: CardRow[]; children: React.ReactElement; containerWidth: number; data: any[] | undefined; loading?: boolean; pagination?: { handleNextPage?: () => void; handlePreviousPage?: () => void; hasNextPage?: boolean; hasPreviousPage?: boolean; itemsPerPage?: number; }; uniqueId: string; } const GridCarouselContext = createContext({}); const GridContainer = styled(motion.div)<{ height: number; itemsPerPage: number }>` display: grid; grid-auto-rows: 0; grid-gap: 18px; grid-template-rows: 1fr; grid-template-columns: repeat(${(props) => props.itemsPerPage || 4}, minmax(0, 1fr)); height: ${(props) => props.height}px; overflow: hidden; `; const Wrapper = styled.div` position: relative; width: 100%; height: 100%; overflow: hidden; `; const variants: Variants = { animate: (custom: { direction: number; loading: boolean }) => { return { opacity: custom.loading ? 0.5 : 1, scale: custom.loading ? 0.95 : 1, transition: { opacity: { duration: 0.2 }, x: { damping: 30, stiffness: 300, type: 'spring' }, }, x: 0, }; }, exit: (custom: { direction: number; loading: boolean }) => { return { opacity: 0, transition: { opacity: { duration: 0.2 }, x: { damping: 30, stiffness: 300, type: 'spring' }, }, x: custom.direction > 0 ? -1000 : 1000, }; }, initial: (custom: { direction: number; loading: boolean }) => { return { opacity: 0, x: custom.direction > 0 ? 1000 : -1000, }; }, }; const Carousel = ({ data, cardRows }: any) => { const { loading, pagination, gridHeight, imageSize, direction, uniqueId } = useContext(GridCarouselContext); const handlePlayQueueAdd = useHandlePlayQueueAdd(); return ( {data?.map((item: any, index: number) => ( ))} ); }; export const GridCarousel = ({ data, loading, cardRows, pagination, children, containerWidth, uniqueId, }: GridCarouselProps) => { const [direction, setDirection] = useState(0); const gridHeight = useMemo( () => (containerWidth * 1.2 - 36) / (pagination?.itemsPerPage || 4), [containerWidth, pagination?.itemsPerPage], ); const imageSize = useMemo(() => gridHeight * 0.66, [gridHeight]); const providerValue = useMemo( () => ({ cardRows, data, direction, gridHeight, imageSize, loading, pagination, setDirection, uniqueId, }), [cardRows, data, direction, gridHeight, imageSize, loading, pagination, uniqueId], ); return ( {children} {data && ( )} ); }; interface TitleProps { children?: React.ReactNode; } const Title = ({ children }: TitleProps) => { const { pagination, setDirection } = useContext(GridCarouselContext); const handleNextPage = useCallback(() => { setDirection(1); pagination?.handleNextPage?.(); }, [pagination, setDirection]); const handlePreviousPage = useCallback(() => { setDirection(-1); pagination?.handlePreviousPage?.(); }, [pagination, setDirection]); return ( {children} ); }; GridCarousel.Title = Title; GridCarousel.Carousel = Carousel;