This repository has no description
1import type { UrlCard, Collection } from '@/api-client';
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?id=${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}