-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[박상준] Week19 #495
The head ref may contain hidden characters: "part3-\uBC15\uC0C1\uC900-week15"
[박상준] Week19 #495
Changes from all commits
650aaaa
e957f73
05c8c2c
55759a3
22741b8
447cd3b
1c30413
23c3207
81d32fe
7f8a9ba
603ec44
cceee4e
5a78e4d
31382aa
5da2477
d06117f
3ac39e8
a86d24b
9a3df14
70afb0d
46e5205
29d4bd4
1478bff
e8bd9ec
bbed201
c158130
dc6e24e
8fcc9b0
cc044d3
9c44f43
d8e5e8d
b647fd5
8efc686
7d61fd2
9993d82
ba2d670
dc65c45
a7547be
fa87972
60a0ab5
1937e8b
c28f12b
8e81eac
2f5349b
9940b9c
e1820b0
3239777
4cf9a4b
c07080c
cae884c
e6312ca
f35a293
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"plugins": ["prettier-plugin-tailwindcss"] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
@import '../styles/color.css'; | ||
@import '../styles/reset.css'; | ||
@tailwind base; | ||
@tailwind components; | ||
@tailwind utilities; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import QueryProvider from "@/ui/providers/queryProvider"; | ||
import "./global.css"; | ||
import Footer from "@/components/Footer/Footer"; | ||
|
||
export default function RootLayout({ | ||
children, | ||
}: { | ||
children: React.ReactNode; | ||
}) { | ||
return ( | ||
<html lang="ko"> | ||
<body> | ||
<QueryProvider>{children}</QueryProvider> | ||
<Footer /> | ||
</body> | ||
</html> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,129 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"use client"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { useState } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { Button } from "@/components/Button/Button"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { Controller, useForm } from "react-hook-form"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { emailPattern } from "@/util/util"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import AuthInput from "@/components/Input/AuthInput"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { signIn } from "next-auth/react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import Image from "next/image"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import eyeIcon from "@/public/eye-on.svg"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import eyeOffIcon from "@/public/eye_off.svg"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { useRouter } from "next/navigation"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
export interface FormValueType { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
id: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
password: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
confirmPassword?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
export default function LoginForm() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
const [textHidden, setTextHidden] = useState(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
handleSubmit, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
control, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
setError, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
formState: { isValid }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
} = useForm<FormValueType>({ mode: "onChange" }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
const router = useRouter(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
const formAction = async (data: FormValueType) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
const result = await signIn("credentials", { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
id: data.id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
password: data.password, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
redirect: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (result?.ok) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
router.push("/folder"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else if (result?.error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
setError("id", { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: "manual", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
message: "아이디를 다시 확인해주세요!", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
setError("password", { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: "manual", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
message: "비밀번호를 다시 확인해주세요!", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+36
to
+47
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. happy path를 먼저 고려하고 if else문을 사용하면 if else로 인해 코드의 nesting이 깊어져요.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
const hiddenText = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
setTextHidden(!textHidden); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+50
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이벤트 핸들러의 경우 리액트 프로젝트의 컨벤션을 따라 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
<form | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
className="flex flex-col justify-start gap-[1rem]" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tailwindcss는 넓이 또는 높이 등 spacing 을 0.25rem 기준으로 제공을 해줍니다. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
onSubmit={handleSubmit(formAction)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div className="gap--[1.2rem] relative flex flex-col items-start"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
<Controller | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
name="id" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
control={control} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
rules={{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
required: "이메일을 입력해주세요!", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
pattern: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
value: emailPattern, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
message: "이메일 형식이 아닙니다!", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
}} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
render={({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
field: { value, onChange, onBlur }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
fieldState: { error }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) => ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
<AuthInput | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
id="email" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
label="이메일" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
value={value} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
onChange={onChange} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
onBlur={onBlur} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
type="text" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
placeholder="이메일" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
size="md" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
error={error} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div className="gap--[1.2rem] relative flex flex-col items-start"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
<Controller | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
name="password" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
control={control} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
rules={{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
required: "비밀번호를 입력해주세요!", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
}} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
render={({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
field: { value, onChange, onBlur }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
fieldState: { error }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) => ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
<AuthInput | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
id="password" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
label="비밀번호" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
value={value} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
onChange={onChange} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
onBlur={onBlur} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
type={textHidden ? "password" : "text"} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
placeholder="비밀번호" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
size="md" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
error={error} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
className="absolute right-[1.5rem] top-[5.5rem] m-0 cursor-pointer border-none p-0" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
onClick={hiddenText} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
<Image | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
src={textHidden ? eyeOffIcon : eyeIcon} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
width={16} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
height={16} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
alt="눈 아이콘" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
<Button size={"lg"} type="submit" buttonActive={!isValid}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. string literal이 attribute으로 전달되는 경우 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
로그인 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
</Button> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
</form> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import Image from "next/image"; | ||
import Link from "next/link"; | ||
import LoginForm from "./_components/loginForm"; | ||
import LogoIcon from "@/public/logo.svg"; | ||
import kakaoIcon from "@/public/Kakao.svg"; | ||
import googleIcon from "@/public/googleIcon.png"; | ||
|
||
export default function Login() { | ||
return ( | ||
<div className="flex h-[100vh] flex-col items-center justify-center bg-[--Background] p-[3.2rem]"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
<div className="flex flex-col content-center items-center gap-[3.2rem]"> | ||
<div className="flex flex-col items-center justify-center gap-[3rem]"> | ||
<div className="flex flex-col justify-center gap-[1.6rem]"> | ||
<Link href="/"> | ||
<Image src={LogoIcon} alt="메인로고" width={210} height={38} /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이미지에 들어가는 alt는 이미지 자체를 설명하도록 하는게 좋아요. |
||
</Link> | ||
<div className="flex items-center justify-center gap-[0.8rem]"> | ||
<span className="text-[1.6rem]">회원이 아니신가요?</span> | ||
<Link href="/signup" style={{ textDecoration: "none" }}> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. textdecoration 필드도 tailwindcss로 override가 가능해요. 한번 살펴볼까요? |
||
<p className="text-[1.6rem] font-[600] text-[--Primary]"> | ||
회원 가입하기 | ||
</p> | ||
</Link> | ||
</div> | ||
</div> | ||
<LoginForm /> | ||
</div> | ||
<div className="flex w-[40rem] items-center justify-between rounded-[0.8rem] border border-solid border-[--Linkbrary-gray20] bg-[--Linkbrary-gray10] px-[2.4rem] py-[1.2rem]"> | ||
<p className="text-[1.4rem] font-[--Linkbrary-gray100]"> | ||
소셜 로그인 | ||
</p> | ||
<div className="flex items-center justify-normal gap-[1.6rem]"> | ||
<Link | ||
href="https://www.google.com/" | ||
target="_blank" | ||
className="flex h-[4.2rem] w-[4.2rem] items-center justify-center rounded-full bg-[--Section-white]" | ||
> | ||
<Image src={googleIcon} alt="구글아이콘" width={22} height={22} /> | ||
</Link> | ||
<Link | ||
href="https://www.kakaocorp.com/page/" | ||
target="_blank" | ||
className="flex h-[4.2rem] w-[4.2rem] items-center justify-center rounded-full bg-[--Kakao-logo-color]" | ||
> | ||
<Image | ||
src={kakaoIcon} | ||
alt="카카오아이콘" | ||
width={26} | ||
height={24} | ||
/> | ||
</Link> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. folder directory를 예를 들면 이런 경우죠, |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { getFolderData, getFolderList, getUserData } from "@/service/api"; | ||
import SharedFolderInfo from "../_components/SharedFolderInfo"; | ||
import SharedFolderContents from "../_components/SharedFolderContents"; | ||
|
||
export default async function SharedFolder({ | ||
params, | ||
}: { | ||
params: { folderId: string }; | ||
}) { | ||
const folderInfo = await getFolderData(params.folderId); | ||
const folderLink = await getFolderList(params.folderId); | ||
Comment on lines
+10
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분 잘 동작했나요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 또한 |
||
const linkList = folderLink?.data ?? []; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이건 불필요한 로직으로 사료되어요. |
||
const owner = await getUserData(folderInfo?.data[0].user_id); | ||
|
||
return ( | ||
<> | ||
<SharedFolderInfo owner={owner.data[0]} folderInfo={folderInfo.data[0]} /> | ||
<div className="mx-auto my-0 flex max-w-[106rem] flex-col items-center justify-center py-[5rem]"> | ||
<SharedFolderContents list={linkList} /> | ||
</div> | ||
</> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Links } from "@/hooks/useGetFolder"; | ||
import SharedLinkItem from "./SharedLinkItem"; | ||
|
||
export default function SharedFolderContents({ list }: { list: Links }) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. props로 전달받는 요소는 배열이지만, 제대로 설명해보자면 링크들을 담은 배열이죠? |
||
return ( | ||
<div className="relative mx-auto my-0 grid gap-[2rem] sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3"> | ||
{list.length > 0 ? ( | ||
list.map((item) => <SharedLinkItem item={item} key={item.id} />) | ||
) : ( | ||
<div className="flex h-[50vh] flex-col items-center justify-center py-[8rem]"> | ||
저장된 링크가 없습니다. | ||
</div> | ||
)} | ||
</div> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { User } from "@/contexts/UserContext"; | ||
import Image from "next/image"; | ||
|
||
interface FolderInfoType { | ||
id: number; | ||
created_at: Date; | ||
favorite: boolean; | ||
name: string; | ||
user_id: number; | ||
} | ||
|
||
export default function SharedFolderInfo({ | ||
owner, | ||
folderInfo, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. folder 하나에 대한 정보인만큼 그냥 folder라고 프롭이름을 설정해주어도 좋지 않을까 생각되어요 |
||
}: { | ||
owner: User; | ||
folderInfo: FolderInfoType; | ||
}) { | ||
return ( | ||
<div className="flex w-full flex-col items-center justify-center bg-[--Background] pb-[6rem] pt-[2rem]"> | ||
<Image | ||
src={owner?.image_source} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이미지가 없다면 empty placeholder라도 들어가면 더 좋은 ux를 제공할 수 있습니다! |
||
alt="owner 이미지" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
width={60} | ||
height={60} | ||
/> | ||
<p className="mt-[1.2rem] h-[2.4rem] text-[1.6rem] font-[400] leading-[2.4rem]"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. inline element에 height를 지정하신 이유가 있나요? |
||
{owner?.name} | ||
</p> | ||
<p className="mt-[2rem] h-[5.5rem] text-[4rem] font-[600] leading-normal"> | ||
{folderInfo?.name} | ||
</p> | ||
</div> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { changeDate, calculateDate } from "@/util/util"; | ||
import Image from "next/image"; | ||
import Link from "next/link"; | ||
import logo from "@/public/logo.svg"; | ||
import { LinkData } from "@/hooks/useGetFolder"; | ||
|
||
export default async function SharedLinkItem({ item }: { item: LinkData }) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. presenter 콤포넌트에서 유틸성 함수들까지 활용해 기능구현을 하고있다보니 기능 관리차원에서 번잡합니다. |
||
const { url, description, image_source, title } = item; | ||
const nowDate = new Date(); | ||
const createDate = changeDate(new Date(item.created_at)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 요 녀석도 <p className="h-[2.4rem] text-[1.4rem]">{formatDate(item.created_at, "yyyy.mm.dd")}</p> |
||
const date = calculateDate( | ||
(Number(nowDate) - Number(new Date(item.created_at))) / 1000, | ||
); | ||
Comment on lines
+11
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. util쪽에서 그냥 <p className="text-[1.3rem] text-[--Description]">
{getTimesAgo(item.created_at)} ago
</p> |
||
|
||
return ( | ||
<Link href={url} target="_blank" rel="noreferrer"> | ||
<div className="relative flex w-[34rem] flex-col items-center rounded-[1.5rem] text-[1.6rem] no-underline shadow-[0_5px_25px_0px_rgba(0,0,0,0.3)]"> | ||
<div className="flex h-[23.5rem] w-full flex-col items-center overflow-hidden rounded-[1.5rem_1.5rem_0_0]"> | ||
{image_source ? ( | ||
<div className="relative h-full w-full transition ease-in hover:scale-[170%]"> | ||
<Image | ||
src={image_source} | ||
alt="카드 이미지" | ||
fill | ||
objectFit="cover" | ||
/> | ||
</div> | ||
) : ( | ||
<div> | ||
<Image src={logo} alt="빈 이미지" width={133} height={24} /> | ||
</div> | ||
)} | ||
</div> | ||
<div className="relative flex w-full flex-col gap-[1rem] rounded-b-[1.5rem] bg-[--Section-white] px-[2rem] py-[1.5rem]"> | ||
<p className="text-[1.3rem] text-[--Description]"> | ||
{date.time} {date.result} ago | ||
</p> | ||
<p className="overflow-hidden text-ellipsis whitespace-nowrap text-[1.4rem]"> | ||
{title ? title : description} | ||
</p> | ||
<p className="h-[2.4rem] text-[1.4rem]">{createDate}</p> | ||
</div> | ||
</div> | ||
</Link> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import Image from "next/image"; | ||
import Link from "next/link"; | ||
import React from "react"; | ||
import Logo from "@/public/logo.svg"; | ||
|
||
export default function SharedFolderLayout({ | ||
children, | ||
}: { | ||
children: React.ReactNode; | ||
}) { | ||
return ( | ||
<div> | ||
<div className="sticky top-0 z-10 w-full bg-[--Background] px-[3.2rem] py-[2rem] lg:px-[20rem]"> | ||
<div className="flex w-fit flex-col items-start justify-center"> | ||
<Link href="/folder"> | ||
<Image src={Logo} alt="메인 로고" width={133} height={24} /> | ||
</Link> | ||
</div> | ||
</div> | ||
{children} | ||
</div> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sj0724
이 아이도 absolute path로 import 해볼까요?