This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

semble / src / webapp / features / cards / components / urlCard / UrlCard.tsx
3.2 kB 116 lines
1import type { UrlCard, Collection } from '@/api-client/types'; 2import { getDomain } from '@/lib/utils/link'; 3import { 4 Card, 5 Image, 6 Text, 7 Stack, 8 Group, 9 Anchor, 10 AspectRatio, 11 Skeleton, 12 Tooltip, 13} from '@mantine/core'; 14import Link from 'next/link'; 15import UrlCardActions from '../urlCardActions/UrlCardActions'; 16import { MouseEvent, Suspense } from 'react'; 17import { useRouter } from 'next/navigation'; 18import styles from './UrlCard.module.css'; 19 20interface Props { 21 size?: 'large' | 'compact' | 'small'; 22 id: string; 23 url: string; 24 cardContent: UrlCard['cardContent']; 25 note?: UrlCard['note']; 26 collections?: Collection[]; 27 currentCollection?: Collection; 28 urlLibraryCount: number; 29 urlIsInLibrary?: boolean; 30 authorHandle?: string; 31} 32 33export default function UrlCard(props: Props) { 34 const domain = getDomain(props.url); 35 const router = useRouter(); 36 37 const handleNavigateToSemblePage = (e: MouseEvent<HTMLElement>) => { 38 e.stopPropagation(); 39 router.push(`/url/${props.cardContent.url}`); 40 }; 41 // TODO: add more sizes 42 43 return ( 44 <Card 45 component="article" 46 radius={'lg'} 47 p={'sm'} 48 flex={1} 49 h={'100%'} 50 withBorder 51 className={styles.root} 52 onClick={handleNavigateToSemblePage} 53 > 54 <Stack justify="space-between" gap={'sm'} flex={1}> 55 <Group justify="space-between" align="start" gap={'lg'}> 56 <Stack gap={0} flex={1}> 57 <Tooltip label={props.url}> 58 <Anchor 59 onClick={(e) => e.stopPropagation()} 60 component={Link} 61 href={props.url} 62 target="_blank" 63 c={'gray'} 64 lineClamp={1} 65 > 66 {domain} 67 </Anchor> 68 </Tooltip> 69 {props.cardContent.title && ( 70 <Text fw={500} lineClamp={2}> 71 {props.cardContent.title} 72 </Text> 73 )} 74 {props.cardContent.description && ( 75 <Text c={'gray'} fz={'sm'} mt={'xs'} lineClamp={3}> 76 {props.cardContent.description} 77 </Text> 78 )} 79 </Stack> 80 {props.cardContent.thumbnailUrl && ( 81 <AspectRatio ratio={1 / 1}> 82 <Image 83 src={props.cardContent.thumbnailUrl} 84 alt={`${props.url} social preview image`} 85 radius={'md'} 86 w={75} 87 h={75} 88 /> 89 </AspectRatio> 90 )} 91 </Group> 92 93 <Suspense 94 fallback={ 95 <Group justify="space-between"> 96 <Group gap={'xs'}> 97 <Skeleton w={22} h={22} /> 98 </Group> 99 <Skeleton w={22} h={22} /> 100 </Group> 101 } 102 > 103 <UrlCardActions 104 cardContent={props.cardContent} 105 id={props.id} 106 authorHandle={props.authorHandle} 107 note={props.note} 108 currentCollection={props.currentCollection} 109 urlLibraryCount={props.urlLibraryCount} 110 urlIsInLibrary={props.urlIsInLibrary!!} 111 /> 112 </Suspense> 113 </Stack> 114 </Card> 115 ); 116}