Skip to content

Commit 3b62074

Browse files
committed
feat(scrollable dynamic maillist): Developed 'MailList' component to display a scrollable list of mail items. Utilized 'useMailStore' for state management, implemented mail selection on click, and displayed item details with labels and badges.
1 parent 1f106b9 commit 3b62074

File tree

1 file changed

+72
-0
lines changed

1 file changed

+72
-0
lines changed

components/mails/mail-list.tsx

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { ComponentProps } from 'react';
2+
import { formatDistanceToNow } from 'date-fns';
3+
4+
import { cn } from '@/lib/utils';
5+
import { Mail, mails } from '@/lib/data';
6+
import { useMailStore } from '@/hooks/use-mail';
7+
import { ScrollArea } from '../ui/scroll-area';
8+
import { Badge } from '../ui/badge';
9+
10+
interface MailListProps {
11+
items: Mail[];
12+
}
13+
14+
export function MailList({ items }: MailListProps) {
15+
const { selected, selectMail } = useMailStore();
16+
17+
return (
18+
<ScrollArea className="h-screen">
19+
<div className="flex flex-col gap-2 p-4 pt-0">
20+
{items.map((item) => (
21+
<button
22+
key={item.id}
23+
className={cn(
24+
'flex flex-col items-start gap-2 rounded-lg border p-3 text-left text-sm transition-all hover:bg-accent',
25+
selected === item.id && 'bg-muted',
26+
)}
27+
onClick={() => selectMail(item.id)}
28+
>
29+
<div className="flex w-full flex-col gap-1">
30+
<div className="flex items-center">
31+
<div className="flex items-center gap-2">
32+
<div className="font-semibold">{item.name}</div>
33+
{!item.read && <span className="flex h-2 w-2 rounded-full bg-blue-600" />}
34+
</div>
35+
<div
36+
className={cn('ml-auto text-xs', selected === item.id ? 'text-foreground' : 'text-muted-foreground')}
37+
>
38+
{formatDistanceToNow(new Date(item.date), {
39+
addSuffix: true,
40+
})}
41+
</div>
42+
</div>
43+
<div className="text-xs font-medium">{item.subject}</div>
44+
</div>
45+
<div className="line-clamp-2 text-xs text-muted-foreground">{item.text.substring(0, 300)}</div>
46+
{item.labels.length ? (
47+
<div className="flex items-center gap-2">
48+
{item.labels.map((label) => (
49+
<Badge key={label} variant={getBadgeVariantFromLabel(label)}>
50+
{label}
51+
</Badge>
52+
))}
53+
</div>
54+
) : null}
55+
</button>
56+
))}
57+
</div>
58+
</ScrollArea>
59+
);
60+
}
61+
62+
function getBadgeVariantFromLabel(label: string): ComponentProps<typeof Badge>['variant'] {
63+
if (['work'].includes(label.toLowerCase())) {
64+
return 'default';
65+
}
66+
67+
if (['personal'].includes(label.toLowerCase())) {
68+
return 'outline';
69+
}
70+
71+
return 'secondary';
72+
}

0 commit comments

Comments
 (0)