feishin/src/renderer/components/virtual-grid/grid-card/grid-card-controls.tsx

206 lines
4.9 KiB
TypeScript
Raw Normal View History

2023-05-17 17:11:33 -07:00
import React, { MouseEvent, useState } from 'react';
2022-12-19 15:59:14 -08:00
import type { UnstyledButtonProps } from '@mantine/core';
2023-03-09 02:26:09 -08:00
import { RiPlayFill, RiHeartFill, RiHeartLine, RiMoreFill } from 'react-icons/ri';
2022-12-19 15:59:14 -08:00
import styled from 'styled-components';
import { _Button } from '/@/renderer/components/button';
2023-01-05 21:59:07 -08:00
import type { PlayQueueAddOptions } from '/@/renderer/types';
2022-12-19 15:59:14 -08:00
import { Play } from '/@/renderer/types';
2023-03-30 06:44:33 -07:00
import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
2023-01-05 21:59:07 -08:00
import { LibraryItem } from '/@/renderer/api/types';
import { useHandleGeneralContextMenu } from '/@/renderer/features/context-menu/hooks/use-handle-context-menu';
import {
ALBUM_CONTEXT_MENU_ITEMS,
ARTIST_CONTEXT_MENU_ITEMS,
} from '/@/renderer/features/context-menu/context-menu-items';
2022-12-19 15:59:14 -08:00
type PlayButtonType = UnstyledButtonProps & React.ComponentPropsWithoutRef<'button'>;
const PlayButton = styled.button<PlayButtonType>`
2023-03-09 02:26:09 -08:00
position: absolute;
2022-12-19 15:59:14 -08:00
display: flex;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
background-color: rgb(255, 255, 255);
border: none;
border-radius: 50%;
opacity: 0.8;
transition: opacity 0.2s ease-in-out;
2023-03-09 02:26:09 -08:00
transition: scale 0.1s ease-in-out;
2022-12-19 15:59:14 -08:00
&:hover {
opacity: 1;
scale: 1.1;
}
&:active {
opacity: 1;
scale: 1;
}
svg {
fill: rgb(0, 0, 0);
stroke: rgb(0, 0, 0);
}
`;
const SecondaryButton = styled(_Button)`
opacity: 0.8;
transition: opacity 0.2s ease-in-out;
transition: scale 0.2s linear;
&:hover {
opacity: 1;
scale: 1.1;
}
&:active {
opacity: 1;
scale: 1;
}
`;
2023-05-17 17:11:33 -07:00
const GridCardControlsContainer = styled.div<{ $isFavorite?: boolean }>`
2023-03-09 02:26:09 -08:00
position: absolute;
z-index: 100;
2022-12-19 15:59:14 -08:00
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
`;
2023-05-17 17:11:33 -07:00
const FavoriteBanner = styled.div`
position: absolute;
top: -50px;
left: -50px;
width: 80px;
height: 80px;
background-color: var(--primary-color);
box-shadow: 0 0 10px 8px rgba(0, 0, 0, 80%);
transform: rotate(-45deg);
content: '';
pointer-events: none;
`;
2022-12-19 15:59:14 -08:00
const ControlsRow = styled.div`
width: 100%;
height: calc(100% / 3);
`;
const BottomControls = styled(ControlsRow)`
2023-03-09 02:26:09 -08:00
position: absolute;
bottom: 0;
2022-12-19 15:59:14 -08:00
display: flex;
2023-03-09 02:26:09 -08:00
gap: 0.5rem;
2022-12-19 15:59:14 -08:00
align-items: flex-end;
2023-03-09 02:26:09 -08:00
justify-content: flex-end;
2022-12-19 15:59:14 -08:00
padding: 1rem 0.5rem;
`;
const FavoriteWrapper = styled.span<{ isFavorite: boolean }>`
svg {
fill: ${(props) => props.isFavorite && 'var(--primary-color)'};
}
`;
export const GridCardControls = ({
itemData,
itemType,
2022-12-20 04:11:06 -08:00
handlePlayQueueAdd,
2023-01-08 00:52:53 -08:00
handleFavorite,
2022-12-19 15:59:14 -08:00
}: {
2023-05-17 17:11:33 -07:00
handleFavorite: (options: {
id: string[];
isFavorite: boolean;
itemType: LibraryItem;
serverId: string;
}) => void;
2022-12-20 04:11:06 -08:00
handlePlayQueueAdd?: (options: PlayQueueAddOptions) => void;
2022-12-19 15:59:14 -08:00
itemData: any;
itemType: LibraryItem;
}) => {
2023-05-17 17:11:33 -07:00
const [isFavorite, setIsFavorite] = useState(itemData?.userFavorite);
2023-03-30 06:44:33 -07:00
const playButtonBehavior = usePlayButtonBehavior();
2022-12-19 15:59:14 -08:00
2022-12-20 04:11:06 -08:00
const handlePlay = async (e: MouseEvent<HTMLButtonElement>, playType?: Play) => {
2022-12-19 15:59:14 -08:00
e.preventDefault();
e.stopPropagation();
2022-12-20 04:11:06 -08:00
handlePlayQueueAdd?.({
byItemType: {
id: [itemData.id],
2022-12-20 04:11:06 -08:00
type: itemType,
},
2023-05-20 14:55:08 -07:00
playType: playType || playButtonBehavior,
2022-12-19 15:59:14 -08:00
});
};
2023-05-17 17:11:33 -07:00
const handleFavorites = async (e: MouseEvent<HTMLButtonElement>, serverId: string) => {
2023-01-08 00:52:53 -08:00
e.preventDefault();
e.stopPropagation();
handleFavorite?.({
id: [itemData.id],
isFavorite: itemData.userFavorite,
itemType,
2023-05-17 17:11:33 -07:00
serverId,
2023-01-08 00:52:53 -08:00
});
2023-05-17 17:11:33 -07:00
setIsFavorite(!isFavorite);
2023-01-08 00:52:53 -08:00
};
const handleContextMenu = useHandleGeneralContextMenu(
itemType,
itemType === LibraryItem.ALBUM ? ALBUM_CONTEXT_MENU_ITEMS : ARTIST_CONTEXT_MENU_ITEMS,
);
2022-12-19 15:59:14 -08:00
return (
2023-05-17 17:11:33 -07:00
<>
{isFavorite ? <FavoriteBanner /> : null}
<GridCardControlsContainer
$isFavorite
className="card-controls"
>
<PlayButton onClick={handlePlay}>
<RiPlayFill size={25} />
</PlayButton>
<BottomControls>
<SecondaryButton
p={5}
variant="subtle"
onClick={(e) => handleFavorites(e, itemData?.serverId)}
>
<FavoriteWrapper isFavorite={itemData?.isFavorite}>
{isFavorite ? (
<RiHeartFill size={20} />
) : (
<RiHeartLine
color="white"
size={20}
/>
)}
</FavoriteWrapper>
</SecondaryButton>
<SecondaryButton
p={5}
variant="subtle"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
handleContextMenu(e, [itemData]);
}}
>
<RiMoreFill
color="white"
size={20}
/>
</SecondaryButton>
</BottomControls>
</GridCardControlsContainer>
</>
2022-12-19 15:59:14 -08:00
);
};