Skip to content
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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
650aaaa
fix: 로그인 유무에 의한 페이지 리다이렉션 설정
sj0724 May 29, 2024
e957f73
fix: userContext 분리 provider 컴포넌트 생성, 커스텀훅 구현
sj0724 May 29, 2024
05c8c2c
fix: react hook form 타입 지정
sj0724 May 30, 2024
55759a3
fix: react-hook-form정상적용
sj0724 Jun 22, 2024
22741b8
Merge pull request #1 from sj0724/fix-input
sj0724 Jun 22, 2024
447cd3b
feat: 리액트 쿼리 설치 및 세팅
sj0724 Jun 22, 2024
1c30413
refactor: user context 데이터 react-query로 변경
sj0724 Jun 23, 2024
23c3207
Merge pull request #2 from sj0724/feature-query
sj0724 Jun 23, 2024
81d32fe
refactor: 폴더 리스트 페이지 전체 로직 리팩토링
sj0724 Jun 24, 2024
7f8a9ba
Merge pull request #3 from sj0724/feature-query
sj0724 Jun 24, 2024
603ec44
feat: 폴더 리스트 리액트 쿼리로 변경
sj0724 Jun 25, 2024
cceee4e
Merge branch 'part3-박상준-week15' into feature-query
sj0724 Jun 25, 2024
5a78e4d
feat: 링크 리스트 리액트 쿼리 적용
sj0724 Jun 25, 2024
31382aa
feat: 검색 기능, debounce기능 추가
sj0724 Jun 25, 2024
5da2477
refactor: 로그인전 user정보 리퀘스트 방지
sj0724 Jun 25, 2024
d06117f
feat: 로그인 페이지 리액트 쿼리 적용
sj0724 Jun 25, 2024
3ac39e8
Merge pull request #4 from sj0724/feature-query
sj0724 Jun 25, 2024
a86d24b
refactor: 링크 공유 페이지 리팩토링
sj0724 Jun 25, 2024
9a3df14
feat: 회원가입 페이지 리액트 쿼리 적용 및 react-hook-form 리팩토링
sj0724 Jun 26, 2024
70afb0d
Merge pull request #5 from sj0724/feature-query
sj0724 Jun 26, 2024
46e5205
refactor: 로그인 페이지 버튼 disabled 옵션 추가 및 스타일 변경
sj0724 Jun 26, 2024
29d4bd4
refactor: 로딩 컴포넌트 포탈에서 렌더링, 페이지 최상단에 위치설정
sj0724 Jun 26, 2024
1478bff
refactor: 회원가입 버튼 disabled 옵션 추가 및 로그인 로직 수정
sj0724 Jun 26, 2024
e8bd9ec
feat: 폴더 추가 리액트 쿼리 적용, 생성시 refetch설정
sj0724 Jun 27, 2024
bbed201
feat: 폴더이름 변경 리액트 쿼리 적용
sj0724 Jun 27, 2024
c158130
fix: api주소 변경으로 인한 코드 수정
sj0724 Jun 27, 2024
dc6e24e
fix: 검색기능 수정
sj0724 Jun 27, 2024
8fcc9b0
feat: shared페이지 리액트 쿼리 적용
sj0724 Jun 27, 2024
cc044d3
fix: 카드 케밥 메뉴, 즐겨찾기 아이콘 설정
sj0724 Jun 27, 2024
9c44f43
feat: 링크 추가 기능 리액트 쿼리 적용 및 사용자 편의성 개선
sj0724 Jun 27, 2024
d8e5e8d
refactor: 카드 리스트 렌더링 오류, 디펜던시값 추가
sj0724 Jun 27, 2024
b647fd5
feat: 링크 삭제 기능 리액트 쿼리 적용
sj0724 Jun 27, 2024
8efc686
feat: 링크 삭제 기능 리액트 쿼리 적용
sj0724 Jun 27, 2024
7d61fd2
refactor: api 리스폰스 도착전 버튼 비활성화 설정
sj0724 Jun 27, 2024
9993d82
Merge pull request #6 from sj0724/feature-query
sj0724 Jun 27, 2024
ba2d670
feat: 링크 즐겨찾기 기능 구현 및 옵티미스틱 업데이트 구현
sj0724 Jun 28, 2024
dc65c45
refactor: 링크 데이터 로직 리팩토링
sj0724 Jun 28, 2024
a7547be
refactor: 즐겨찾기 폴더 수정, 삭제 버튼 제거
sj0724 Jun 28, 2024
fa87972
fix: 빌드 오류 캐시 데이터 타입 지정 및 공유 페이지 수정
sj0724 Jun 28, 2024
60a0ab5
Merge pull request #7 from sj0724/feature-query
sj0724 Jun 28, 2024
1937e8b
fix: 모달 외부 클릭, esc클릭시 모달 close, 케밥 close 옵션 수정
sj0724 Jun 28, 2024
c28f12b
fix: 링크 추가시 인풋 value 초기화
sj0724 Jun 28, 2024
8e81eac
Merge pull request #8 from sj0724/feature-query
sj0724 Jun 28, 2024
2f5349b
feat: nextAuth 적용, 미들웨어 적용, 로그인 로직 리액트 쿼리 삭제
sj0724 Jul 1, 2024
9940b9c
Merge pull request #9 from sj0724/feature-nextauth
sj0724 Jul 1, 2024
e1820b0
refactor: 로그인 페이지 앱라우터로 리펙토링
sj0724 Jul 1, 2024
3239777
refactor: 회원가입 페이지 앱라우터로 마이그레이션
sj0724 Jul 2, 2024
4cf9a4b
refactor: 공유 페이지 앱라우터로 리팩토링
sj0724 Jul 2, 2024
c07080c
fix: 폴더 공유 링크 수정
sj0724 Jul 2, 2024
cae884c
Merge pull request #10 from sj0724/refactor-approuter
sj0724 Jul 2, 2024
e6312ca
fix: 링크 경로 수정
sj0724 Jul 3, 2024
f35a293
Merge pull request #11 from sj0724/refactor-approuter
sj0724 Jul 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"plugins": ["prettier-plugin-tailwindcss"]
}
5 changes: 5 additions & 0 deletions app/global.css
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;
18 changes: 18 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import QueryProvider from "@/ui/providers/queryProvider";
import "./global.css";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

이 아이도 absolute path로 import 해볼까요?

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>
);
}
129 changes: 129 additions & 0 deletions app/login/_components/loginForm.tsx
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 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

formvaluetype 이라는 이름보단 우리가 이 폼을 통해 어떤 정보를 관리할지에 대한 네이밍이 들어가면 어떨까요?

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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

happy path를 먼저 고려하고 if else문을 사용하면 if else로 인해 코드의 nesting이 깊어져요.
다음과 같이 early return을 통해 조금 더 간결하게 작성해보면 어떨까요?

Suggested change
if (result?.ok) {
router.push("/folder");
} else if (result?.error) {
setError("id", {
type: "manual",
message: "아이디를 다시 확인해주세요!",
});
setError("password", {
type: "manual",
message: "비밀번호를 다시 확인해주세요!",
});
}
if (result?.error) {
setError("id", {
type: "manual",
message: "아이디를 다시 확인해주세요!",
});
setError("password", {
type: "manual",
message: "비밀번호를 다시 확인해주세요!",
});
return
}
router.push("/folder");
}

};

const hiddenText = () => {
setTextHidden(!textHidden);
};
Comment on lines +50 to +52
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

이벤트 핸들러의 경우 리액트 프로젝트의 컨벤션을 따라 handle~~~ 또는 on~~~ 와 같은 네임을 사용해볼까요?
이 경우라면, handleTogglePasswordVisibilityonClickPasswordToggle 과 같은 네임도 좋겠어요.


return (
<form
className="flex flex-col justify-start gap-[1rem]"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

tailwindcss는 넓이 또는 높이 등 spacing 을 0.25rem 기준으로 제공을 해줍니다.
따라서 gap-[1rem] 은 결국 gap-4 와 같아요.
이미 제공되는 템플릿에 존재하는 값이라면 템플릿을 사용해보도록 할까요?

onSubmit={handleSubmit(formAction)}
>
<div className="gap--[1.2rem] relative flex flex-col items-start">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

gap--[1.2rem] 은 오타로 보여요!

<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}>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

string literal이 attribute으로 전달되는 경우 size={"lg"} 처럼 js처리를 하기보단 size="lg" 처럼 바로 string literal을 전달해보면 어떨까요?

로그인
</Button>
</form>
);
}
57 changes: 57 additions & 0 deletions app/login/page.tsx
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]">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

h-[100vh]는 결국 h-screen 이라는 녀석으로 tailwindcss에서 제공하고 있어요.
또한 bg-[--Background] 의 경우 css variable을 사용하고자 하신듯한데, bg-[var(--background)] 로 해야 적용되지 않나요?

<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} />
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

이미지에 들어가는 alt는 이미지 자체를 설명하도록 하는게 좋아요.
메인로고의 경우, 시각장애인이 바로 판단하기 어려울 수 있기 때문에 브랜드 로고등으로 이야기를 해주는게 좋습니다.

</Link>
<div className="flex items-center justify-center gap-[0.8rem]">
<span className="text-[1.6rem]">회원이 아니신가요?</span>
<Link href="/signup" style={{ textDecoration: "none" }}>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

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>
);
}
23 changes: 23 additions & 0 deletions app/sharedFolder/[[...folderId]]/page.tsx
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

folder directory를 [[...]] 로 두신 이유가 있나요?
지금 구조로 보면, folderId 하나만 url로 들어오는걸로 보이는데, 중첩된 id가 url로 들어올 수 있나요?

예를 들면 이런 경우죠, https://my-app.com/sharedFolder/12345/12345/55572

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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

이 부분 잘 동작했나요?
catch-all segment로 동작하면 params에 { folderId: ["..."]}로 배열로 들어오지 싶은데요

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

또한 getFolderDatagetFolderList는 우리가 사용할 결과물만 반환하도록 하면 어떨까요?
위 함수들은 우리가 멘토링 떄 이야기 했던 서비스 레이어에 해당하는데, 이 서비스 레이어에서는 바로 사용할 수 있는 결과물을 반환하도록 해서 이 서비스를 소비하는 부분에서는 데이터 파싱 또는 전처리를 굳이 하지 않아도 되게 하는게 좋겠어요.

const linkList = folderLink?.data ?? [];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

이건 불필요한 로직으로 사료되어요.
folderLink라는 값이 잘 불러와졌고, 위에 멘션드린 것 처럼 service레이어에서 데이터 파싱까지 처리한 후 반환해준다면,
어차피 서버에서 반환해준 배열 데이터가 들어올테니깐요.

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>
</>
);
}
16 changes: 16 additions & 0 deletions app/sharedFolder/_components/SharedFolderContents.tsx
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 }) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

props로 전달받는 요소는 배열이지만, 제대로 설명해보자면 링크들을 담은 배열이죠?
그럼 links라고 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>
);
}
35 changes: 35 additions & 0 deletions app/sharedFolder/_components/SharedFolderInfo.tsx
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,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

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}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

이미지가 없다면 empty placeholder라도 들어가면 더 좋은 ux를 제공할 수 있습니다!

alt="owner 이미지"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

owner 이미지는 사실 아무 정보도 전달하지 않지요.
어차피 owner정보를 받아오는데 그 owner의 이름이나 닉네임등을 사용해

width={60}
height={60}
/>
<p className="mt-[1.2rem] h-[2.4rem] text-[1.6rem] font-[400] leading-[2.4rem]">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

inline element에 height를 지정하신 이유가 있나요?

{owner?.name}
</p>
<p className="mt-[2rem] h-[5.5rem] text-[4rem] font-[600] leading-normal">
{folderInfo?.name}
</p>
</div>
);
}
46 changes: 46 additions & 0 deletions app/sharedFolder/_components/SharedLinkItem.tsx
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 }) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

presenter 콤포넌트에서 유틸성 함수들까지 활용해 기능구현을 하고있다보니 기능 관리차원에서 번잡합니다.
presenter는 전달받은 데이터를 바로 보여줄 수 있도록, 최대한 멍청하게 구현하는게 좋아요!
따라서 날짜 연산 또는 날짜 포맷 파싱과 같은 기능은 util에서 다 처리하도록 해주고, 프레젠터는 그 결과물만 받아와 사용하도록 해볼까요?

const { url, description, image_source, title } = item;
const nowDate = new Date();
const createDate = changeDate(new Date(item.created_at));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

요 녀석도 formatDate 이라는 함수를 만들어 사용하면 어떤가요?

<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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sj0724

util쪽에서 그냥 getTimeAgo 라는 함수를 만들어 문자열로 만들어진 결과를 반환하도록 해서 사용하는건 어떤가요?

 <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>
);
}
23 changes: 23 additions & 0 deletions app/sharedFolder/layout.tsx
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>
);
}
Loading
Loading