Skip to content

Commit 925edfb

Browse files
authored
Merge pull request #23 from codeit9-temporary/feature/Card-ui컴포넌트-구현
Feat: CardItem 컴포넌트 구현, timeAgo 유틸함수 구현, star.svg kebab.svg 다운로드
2 parents 3117afb + 281a905 commit 925edfb

File tree

7 files changed

+129
-3
lines changed

7 files changed

+129
-3
lines changed

components/CardItem.tsx

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { useState } from "react";
2+
import timeAgo from "@/util/timAgo";
3+
import Image from "next/image";
4+
5+
interface linkDataType {
6+
id: number;
7+
title: string;
8+
description: string;
9+
favorite: boolean;
10+
imageSource: string;
11+
url: string;
12+
createdAt: string;
13+
}
14+
15+
const CardItem = (info: linkDataType) => {
16+
const [isSubscribed, seIsSubscribed] = useState(false);
17+
const [isOpen, setIsOpen] = useState(false);
18+
19+
const formattedDate = info.createdAt?.slice(0, 10).replace(/-/g, ".");
20+
const createdTime = timeAgo(info.createdAt);
21+
22+
return (
23+
<div className="w-[340px] h-[344px] rounded-[12px] shadow-lg mt-20 ml-20 overflow-hidden cursor-pointer hover:scale-105 hover:duration-300">
24+
<section className="relative w-full h-[60%]">
25+
<Image
26+
src={info.imageSource || `/images/no-content.svg`}
27+
objectFit="cover"
28+
alt="링크 미리보기"
29+
fill
30+
/>
31+
{isSubscribed ? (
32+
<div
33+
onClick={() => seIsSubscribed(!isSubscribed)}
34+
className="absolute top-[15px] right-[15px] z-1"
35+
>
36+
<Image
37+
src="/icons/star-fill.svg"
38+
width={32}
39+
height={32}
40+
alt="subscripe button"
41+
/>
42+
</div>
43+
) : (
44+
<div
45+
onClick={() => seIsSubscribed(!isSubscribed)}
46+
className="absolute top-[15px] right-[15px] z-1"
47+
>
48+
<Image
49+
src="/icons/star-empty.svg"
50+
width={32}
51+
height={32}
52+
alt="subscripe button"
53+
/>
54+
</div>
55+
)}
56+
</section>
57+
58+
<section className="w-full h-[40%] flex flex-col justify-between gap-[10px] pt-[15px] px-[20px] pb-[10px]">
59+
<div className="flex justify-between">
60+
<span className="text-sm text-gray-400">
61+
{createdTime || "1일 전"}
62+
</span>
63+
<div
64+
className="relative w-[21px] h-[17px]"
65+
onClick={(state) => setIsOpen(!state)}
66+
>
67+
<Image src="/icons/kebab.svg" alt="kebab button" fill />
68+
</div>
69+
</div>
70+
<div className="text-[black100] text-lg ">
71+
{info.description || "설명"}
72+
</div>
73+
<div className="text-sm text-[black200]">
74+
{formattedDate || "2024.11.06"}
75+
</div>
76+
</section>
77+
</div>
78+
);
79+
};
80+
81+
export default CardItem;

pages/index.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
1-
export default function Home() {
2-
return <div>인덱스 페이지</div>;
3-
}
1+
export default function Home() {}

public/icons/kebab.svg

Lines changed: 5 additions & 0 deletions
Loading

public/icons/star-empty.svg

Lines changed: 3 additions & 0 deletions
Loading

public/icons/star-fill.svg

Lines changed: 4 additions & 0 deletions
Loading

public/images/no-content.svg

Lines changed: 14 additions & 0 deletions
Loading

util/timAgo.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
function timeAgo(createdAt: string): string {
2+
const createdDate = new Date(createdAt);
3+
const currentDate = new Date();
4+
5+
const secondsDiff = Math.floor(
6+
(currentDate.getTime() - createdDate.getTime()) / 1000
7+
);
8+
const minutesDiff = Math.floor(secondsDiff / 60);
9+
const hoursDiff = Math.floor(minutesDiff / 60);
10+
const daysDiff = Math.floor(hoursDiff / 24); //
11+
12+
if (hoursDiff < 1) {
13+
return `${secondsDiff}초 전`;
14+
} else if (hoursDiff < 24) {
15+
return `${hoursDiff}시간 전`;
16+
} else {
17+
return `${daysDiff}일 전`;
18+
}
19+
}
20+
21+
export default timeAgo;

0 commit comments

Comments
 (0)