Files
TriggerFrontend/src/pages/settings/components/Theming/Themes/ThemeCard.tsx
2025-07-21 16:28:43 -05:00

216 lines
5.8 KiB
TypeScript

import { Box, Button, Group, Overlay, Stack, Text } from '@mantine/core';
import {
useDebouncedState,
useDisclosure,
useElementSize,
useHover,
} from '@mantine/hooks';
import { DeleteItemModal } from 'components';
import { useCommonHooks } from 'hooks';
import type { Theme, ThemePlaylist } from 'types';
import { MiniAppItem, MiniGroupItem, ThemeManagementPill } from '.';
export function ThemeCard({
cardTheme,
handleOpen,
allThemes,
themePlaylists,
}: {
cardTheme: Theme;
handleOpen: (cardTheme: Theme) => void;
allThemes: Theme[];
themePlaylists: ThemePlaylist[];
}) {
const { hovered, ref: hoverRef } = useHover();
const { ref, width } = useElementSize();
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
const { currentTheme, setCurrentTheme, setCurrentThemePlaylist, handleDelete } =
useCommonHooks();
const [hoverPreview, setHoverPreview] = useDebouncedState(false, 1000);
const [transition, setTransition] = useDebouncedState(false, 200);
return (
<Group
gap={0}
align='center'
justify='center'
display={'grid'}
pos={'relative'}
ref={hoverRef}
>
<DeleteItemModal
modalOpened={modalOpened}
handleClose={closeModal}
handleDelete={() => handleDelete(cardTheme, 'api/themes')}
title={'Delete Theme'}
body={
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
<Text>Are you sure you want to delete this theme?</Text>
<Text
style={{
fontWeight: 'bold',
fontSize: '1.25rem',
padding: '.5rem',
margin: '.5rem',
borderRadius: '10px',
backgroundColor: 'var(--mantine-color-accent-0)',
color: 'var(--mantine-color-background-0)',
}}
>{`"${cardTheme.name}"`}</Text>
<Text c='red'>This action cannot be undone!</Text>
</Stack>
}
/>
<Text
style={{
position: 'absolute',
top: -10,
left: 6,
paddingRight: '.25rem',
paddingLeft: '.25rem',
backgroundColor: cardTheme.backgroundColor,
borderRadius: '4px',
color:
cardTheme.borderColor === cardTheme.primaryColor
? cardTheme.accentColor
: cardTheme.primaryColor,
zIndex: 3,
boxShadow: `2px -2px ${cardTheme.borderColor}`,
textOverflow: 'ellipsis',
overflow: 'hidden',
whiteSpace: 'nowrap',
maxWidth: width,
}}
>
{cardTheme.name}
</Text>
<Group
style={{
width: '100%',
height: '100%',
overflow: 'hidden',
transition: 'all .2s ease',
position: 'absolute',
}}
>
<ThemeManagementPill
allThemes={allThemes}
cardTheme={cardTheme}
handleOpen={handleOpen}
themePlaylists={themePlaylists}
openModal={openModal}
hovered={hovered}
hoverPreview={hoverPreview}
setHoverPreview={setHoverPreview}
transition={transition}
setTransition={setTransition}
/>
</Group>
<Button
ref={ref}
w={'275px'}
h={'115px'}
disabled={currentTheme === 'random'}
style={{
backgroundImage:
cardTheme?.backgroundImage.toLocaleLowerCase() !== 'none'
? `linear-gradient(${cardTheme?.backgroundColor}33, ${cardTheme?.backgroundColor}33), url(../../api/backgroundImages/thumbs/${cardTheme?.backgroundImage})`
: undefined,
backgroundSize:
cardTheme?.backgroundImage.toLocaleLowerCase() !== 'none'
? 'cover'
: undefined,
backgroundColor:
cardTheme?.backgroundImage.toLocaleLowerCase() === 'none'
? cardTheme?.backgroundColor
: undefined,
backgroundPosition: 'center',
border: `solid ${cardTheme.borderColor}`,
filter:
(cardTheme.randomEnabled === 0 && !hoverPreview) || transition
? 'saturate(0)'
: undefined,
transition: 'all .25s ease',
}}
onClick={() => {
setCurrentTheme(cardTheme.name);
setCurrentThemePlaylist('All');
}}
>
{hovered && currentTheme !== 'random' && (
<Overlay
style={{
opacity: !hoverPreview || transition ? 0.5 : 0,
transition: 'all .25s ease',
}}
zIndex={1}
/>
)}
<Group w={'100%'} gap={0} display={'flex'} align='center' justify='center'>
<Stack align='center' gap={12}>
<Box
style={{
height: '8px',
width: '100px',
backgroundColor: cardTheme.searchColor,
borderRadius: '4px',
borderBottom: `solid 1px ${cardTheme.borderColor}`,
}}
/>
<Group justify='space-between'>
<Box
style={{
height: '.5rem',
width: '100px',
backgroundColor: cardTheme.accentColor,
borderRadius: '4px',
}}
/>
<Box
style={{
height: '.5rem',
width: '50px',
backgroundColor: cardTheme.primaryColor,
borderRadius: '4px',
}}
/>
</Group>
<Group w={'100%'} mb={-4}>
<Box
style={{
height: '2px',
width: '40px',
backgroundColor: cardTheme.primaryColor,
borderRadius: '4px',
}}
/>
</Group>
<Group w={'100%'} gap={10} justify='space-between'>
<MiniAppItem cardTheme={cardTheme} />
<MiniAppItem cardTheme={cardTheme} />
<MiniAppItem cardTheme={cardTheme} />
<MiniAppItem cardTheme={cardTheme} />
</Group>
<Group w={'100%'} mb={-4}>
<Box
style={{
height: '2px',
width: '32px',
backgroundColor: cardTheme.primaryColor,
borderRadius: '4px',
}}
/>
</Group>
<Group w={'100%'} gap={10} justify='space-between'>
<MiniGroupItem cardTheme={cardTheme} />
<MiniGroupItem cardTheme={cardTheme} />
<MiniGroupItem cardTheme={cardTheme} />
<MiniGroupItem cardTheme={cardTheme} />
</Group>
</Stack>
</Group>
</Button>
</Group>
);
}