Files
Homarr/src/components/AppShelf/AppShelfItem.tsx

145 lines
4.2 KiB
TypeScript
Raw Normal View History

2022-08-26 19:52:20 -04:00
import { useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import {
Anchor,
AspectRatio,
2022-08-26 19:52:20 -04:00
Card,
Center,
createStyles,
Image,
2022-08-26 19:52:20 -04:00
Text,
useMantineColorScheme,
} from '@mantine/core';
import { motion } from 'framer-motion';
import { useState } from 'react';
import PingComponent from '../../modules/ping/PingModule';
import { useConfig } from '../../tools/state';
2022-08-26 19:52:20 -04:00
import { serviceItem } from '../../tools/types';
const useStyles = createStyles((theme) => ({
item: {
transition: 'box-shadow 150ms ease, transform 100ms ease',
'&:hover': {
boxShadow: `${theme.shadows.md} !important`,
transform: 'scale(1.05)',
},
[theme.fn.smallerThan('sm')]: {
WebkitUserSelect: 'none',
},
},
}));
2022-11-22 13:58:50 +09:00
export function SortableItem(props: any) {
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({
id: props.id,
});
const style = {
transform: CSS.Transform.toString(transform),
transition,
};
return (
<div ref={setNodeRef} style={style} {...attributes} {...listeners}>
2022-11-22 13:58:50 +09:00
{props.children}
</div>
);
}
export function AppShelfItem(props: any) {
const { service }: { service: serviceItem } = props;
const [hovering, setHovering] = useState(false);
const { config } = useConfig();
const { colorScheme } = useMantineColorScheme();
const { classes } = useStyles();
return (
<motion.div
animate={{
scale: [0.9, 1.06, 1],
rotate: [0, 5, 0],
}}
transition={{ duration: 0.6, type: 'spring', damping: 10, mass: 0.75, stiffness: 100 }}
key={service.name}
onHoverStart={() => {
setHovering(true);
}}
onHoverEnd={() => {
setHovering(false);
}}
>
<Card
withBorder
radius="lg"
shadow="md"
className={classes.item}
style={{
2022-11-22 13:58:50 +09:00
// Use the grab cursor when hovering over the card
cursor: hovering ? 'grab' : 'auto',
background: `rgba(${colorScheme === 'dark' ? '37, 38, 43,' : '255, 255, 255,'} \
${(config.settings.appOpacity || 100) / 100}`,
borderColor: `rgba(${colorScheme === 'dark' ? '37, 38, 43,' : '233, 236, 239,'} \
${(config.settings.appOpacity || 100) / 100}`,
}}
>
<Card.Section>
<Anchor
target={service.newTab === false ? '_top' : '_blank'}
href={service.openedUrl ? service.openedUrl : service.url}
style={{ color: 'inherit', fontStyle: 'inherit', fontSize: 'inherit' }}
>
<Text mt="sm" align="center" lineClamp={1} weight={550}>
{service.name}
</Text>
</Anchor>
<motion.div
style={{
position: 'absolute',
top: 15,
right: 15,
alignSelf: 'flex-end',
}}
animate={{
opacity: hovering ? 1 : 0,
}}
>
2022-12-11 00:00:11 +01:00
{/* <TileMenu service={service} /> TODO: Remove this component */}
</motion.div>
</Card.Section>
2022-09-29 16:34:28 +09:00
<Card.Section>
<Center>
<AspectRatio
ratio={3 / 5}
2022-09-29 16:34:28 +09:00
m="lg"
style={{
2022-09-29 16:34:28 +09:00
height: 75 * ((config.settings.appCardWidth ?? 1) * 1.2),
width: 75 * ((config.settings.appCardWidth ?? 1) * 2),
}}
>
<motion.i
whileHover={{
scale: 1.1,
}}
>
<Anchor
href={service.openedUrl ?? service.url}
target={service.newTab === false ? '_top' : '_blank'}
>
<Image
styles={{ root: { cursor: 'pointer' } }}
2022-09-29 16:34:28 +09:00
width={75 * ((config.settings.appCardWidth ?? 1) * 1.2)}
height={75 * ((config.settings.appCardWidth ?? 1) * 1.2)}
src={service.icon}
fit="contain"
/>
</Anchor>
</motion.i>
</AspectRatio>
2022-08-26 19:52:20 -04:00
{service.ping !== false && <PingComponent url={service.url} status={service.status} />}
2022-09-29 16:34:28 +09:00
</Center>
</Card.Section>
</Card>
</motion.div>
);
2022-11-22 14:05:03 +09:00
}