-
-
Notifications
You must be signed in to change notification settings - Fork 449
Expand file tree
/
Copy pathCard.tsx
More file actions
124 lines (114 loc) · 3.14 KB
/
Card.tsx
File metadata and controls
124 lines (114 loc) · 3.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import React from 'react';
import Link from 'next/link';
import TextTruncate from 'react-text-truncate';
import Image from 'next/image';
import { Card as ShadcnCard } from '@/components/ui/card';
import { Separator } from '@/components/ui/separator';
import { cn } from '@/lib/utils';
export interface CardProps {
title: string;
body: string;
icon?: string;
link?: string;
image?: string;
extended?: boolean;
headerSize?: 'small' | 'medium' | 'large';
bodyTextSize?: 'small' | 'medium' | 'large';
}
const CardBody = ({
title,
body,
icon,
link,
image,
extended,
headerSize = 'medium',
bodyTextSize = 'medium',
}: CardProps) => {
const headerSizeClasses = {
small: 'text-[0.9rem]',
medium: 'text-[1.3rem]',
large: 'text-[2rem]',
};
const bodyTextSizeClasses = {
small: 'text-[0.85rem]',
medium: 'text-[1rem]',
large: 'text-[1.5rem]',
};
return (
<ShadcnCard className='group relative h-full w-full rounded-lg border border-gray-200 bg-white p-6 px-12 shadow-3xl transition-colors ease-in-out hover:bg-slate-100 dark:bg-slate-800 dark:shadow-2xl dark:shadow-slate-900 hover:dark:bg-slate-900/30'>
{image && (
<div className='flex justify-center'>
<Image
src={image}
alt={title}
width={384}
height={128}
className='h-32 object-contain p-2'
data-test='card-image'
/>
</div>
)}
<div className='flex flex-row items-start'>
{icon && (
<span className='mr-6 flex h-14 w-14 flex-shrink-0 items-center justify-center rounded-lg border bg-blue-200 px-3 text-gray-900 dark:text-white'>
<Image
src={icon}
alt={title}
width={56}
height={56}
className='h-full w-full'
data-test='card-icon'
/>
</span>
)}
<p
className={cn(
'mb-1 mt-1 items-center font-bold text-gray-900 dark:text-white',
headerSizeClasses[headerSize],
)}
data-test='card-title'
>
{title}
</p>
</div>
<Separator className='bg-gray-400' />
<p
className={cn(
'mb-8 mt-5 text-black dark:text-white',
bodyTextSizeClasses[bodyTextSize],
)}
data-test='card-body'
>
{extended ? (
<span dangerouslySetInnerHTML={{ __html: body }} />
) : (
<TextTruncate element='span' line={3} text={body} />
)}
</p>
{link && (
<p
className='absolute bottom-3 right-5 font-medium opacity-0 transition-opacity delay-150 ease-in-out group-hover:opacity-100 text-black dark:text-white'
data-test='card-read-more'
>
Read More
</p>
)}
</ShadcnCard>
);
};
const Card: React.FC<CardProps> = ({ link, ...props }) => {
return link ? (
<Link
href={link}
target='_blank'
rel='noopener noreferrer'
data-test='card-link'
>
<CardBody link={link} {...props} />
</Link>
) : (
<CardBody {...props} />
);
};
export default Card;