Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
21 changes: 20 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"next": "13.5.6",
"react": "^18",
"react-dom": "^18",
"recoil": "^0.7.7"
"recoil": "^0.7.7",
"swiper": "^11.1.3"
},
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
Expand Down
5 changes: 5 additions & 0 deletions public/PublicBadge.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
62 changes: 62 additions & 0 deletions src/app/api/public/data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
[
{
"id": "1",
"title": "데이터 1",
"description": "이것은 데이터 1입니다.",
"time": "10:00"
},
{
"id": "2",
"title": "데이터 2",
"description": "이것은 데이터 2입니다.",
"time": "11:00"
},
{
"id": "3",
"title": "데이터 3",
"description": "이것은 데이터 3입니다.",
"time": "12:00"
},
{
"id": "4",
"title": "데이터 4",
"description": "이것은 데이터 4입니다.",
"time": "13:00"
},
{
"id": "5",
"title": "데이터 5",
"description": "이것은 데이터 5입니다.",
"time": "14:00"
},
{
"id": "6",
"title": "데이터 6",
"description": "이것은 데이터 6입니다.",
"time": "15:00"
},
{
"id": "7",
"title": "데이터 7",
"description": "이것은 데이터 7입니다.",
"time": "16:00"
},
{
"id": "8",
"title": "데이터 8",
"description": "이것은 데이터 8입니다.",
"time": "17:00"
},
{
"id": "9",
"title": "데이터 9",
"description": "이것은 데이터 9입니다.",
"time": "18:00"
},
{
"id": "10",
"title": "데이터 10",
"description": "이것은 데이터 10입니다.",
"time": "19:00"
}
]
7 changes: 7 additions & 0 deletions src/app/api/public/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { NextResponse } from 'next/server';

import data from './data.json';

export async function GET(request: any) {
return NextResponse.json(data, { status: 200 });
}
8 changes: 8 additions & 0 deletions src/app/create/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { logging } from '@/services/mixpanel';
import { axiosPostBoard } from '@/utils/apiInterface';
import { confirm } from '@/utils/confirm';
import { defaultState } from '@/utils/theme/default';
import { toggleDialog } from '@/utils/toggleDialo';

export default function Create() {
const [openModal, closeModal] = useModal();
Expand All @@ -29,6 +30,12 @@ export default function Create() {
};

const handleConfirm = async () => {
const isPublic = await toggleDialog(
openModal,
closeModal,
'잠깐! 🙌',
'공개하기를 선택하면 내가 만든\n 스트링캣이 랜덤으로 홈에 공개돼요!',
);
const isConfirmed = await confirm(
openModal,
closeModal,
Expand All @@ -38,6 +45,7 @@ export default function Create() {
if (isConfirmed) {
logging('click_submit_board_confirm', 'create');
const data = {
public: isPublic,
theme: themelist[preview - 1],
title: `${title}`,
};
Expand Down
1 change: 1 addition & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
body {
-ms-overflow-style: none;
}

::-webkit-scrollbar {
display: none;
}
9 changes: 3 additions & 6 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
'use client';

import { RecoilRoot } from 'recoil';

import Script from 'next/script';

import './globals.css';
Expand All @@ -10,6 +6,7 @@ import Description from '@/component/Common/Description';
import Modal from '@/component/Common/Modal';
import OpenGraph from '@/component/Common/OpenGraph';
import InApp from '@/component/InApp';
import RecoilWrapper from '@/component/RecoilWrapper';

export default function RootLayout({
children,
Expand Down Expand Up @@ -46,11 +43,11 @@ export default function RootLayout({
<body className="h-full overscroll-none bg-black/80">
<div className="m-auto h-full max-w-md font-pretentdard">
<InApp />
<RecoilRoot>
<RecoilWrapper>
Copy link
Contributor

Choose a reason for hiding this comment

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

recoilroot를 recoilwrapper로 변경하신 이유가 있나요?

Copy link
Contributor

Choose a reason for hiding this comment

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

recoilRoot가 하던 일과 동일한 행동을 recoilWrapper에서 하고 있는 것 같아서 저도 궁금합니다!
파일을 분리하신 이유가 있으실까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

layout 파일 상단에 'use client' 를 지우고 next js의 이점인 pre rendering을 사용 하기 위해 RecoilWrapper로 묶었습니다.

use client를 지우면 layout파일에서 내부에서 state와 같은 클라이언트 코드를 사용할 수 없기 때문에
클라이언트 코드들을 layout 파일에서 지워야 합니다.
변경 하기 전 RecoilRoot와 같은 경우 내부에 있는 state 때문에 RecoilRoot를 호출하는 컴포넌트는 무조건 'use client'로
선언되어 있어야 합니다
따라서 RecoilRoot컴포넌트를 RecoilWrapper로 감싸고 그 내부에서 'use client' 를 호출하는 방식으로 해결하였습니다.

아래 설명은 layout에 use client를 제거한 생각의 근거 입니다.

일반적인 next js 프로젝트에서 layout 코드를 서버쪽에서 호출하게 만드는 게 일반적 입니다.
next js 가이드에서도 그렇게 안내 되어 있습니다.
현재 프로젝트 layout.tsx 파일 상단에는 'use client' 로 선언되어 있는데,
이때문에 layout 페이지가 서버에서 pre rendering 되는 게 아닌 클라이언트 쪽에서 rendering 될 것으로 예상 됩니다.
이는 pre rendering을 사용해서 얻는 next js 의 SEO 장점과 웹 페이지 로딩 속도 면에서 빨라지는 이점이 use client를 사용해서 사라지기 때문에 지워야 한다고 생각 들었습니다

<AxiosInterceptor />
<Modal />
{children}
</RecoilRoot>
</RecoilWrapper>
</div>
</body>
</html>
Expand Down
34 changes: 15 additions & 19 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,21 @@ import { useEffect, useRef, useState } from 'react';
import Image from 'next/image';
import { useRouter } from 'next/navigation';

import { AnimationVideo } from '@/component/Common/AnimationVideo';
import HeaderLayout from '@/component/Common/HeaderLayout';
import MainManStrcat from '@/component/MainManStrcat';
import OpenStrcatBoard from '@/component/OpenStrcatBoard';
import { useLogin } from '@/hooks/useLogin';
import { bodyFontState } from '@/recoil/font/body';
import { titleFontState } from '@/recoil/font/title';
import { logging } from '@/services/mixpanel';
import { axiosGetPublicBoard } from '@/utils/apiInterface';
import { focusToHighlight } from '@/utils/focusToHighlight';
import { defaultState } from '@/utils/theme/default';

export default function Home() {
const [isLogin] = useLogin();
const router = useRouter();
const [openBoard, setOpenBoard] = useState([]);
const ref = useRef<HTMLHeadingElement | null>(null);
const [windowHeight, setWindowHeight] = useState(0);

Expand All @@ -26,6 +28,11 @@ export default function Home() {
if (window) setWindowHeight(window.innerHeight);
}, []);

useEffect(() => {
axiosGetPublicBoard().then((res) => {
setOpenBoard(res.data);
});
}, []);
const handleClickPersonal = () => {
logging('click_create_board', 'main');
if (isLogin) router.push('create', { scroll: false });
Expand All @@ -51,25 +58,14 @@ export default function Home() {
>
함께 문장을 이어가는 롤링페이퍼
</div>
<div className="flex flex-col items-center justify-center pt-[64px]">
<div className="relative">
<Image
src="/MainImage.svg"
width={153}
height={153}
alt="mainStrcatIcon"
priority
/>
<div className="absolute top-0">
<AnimationVideo
src="/SnowAnimation.webm"
width={153}
height={153}
/>
</div>
</div>
<div className="px-[24px] pt-[32px] text-default-white ">
다른 사람이 공개한 스트링켓이에요
</div>
<OpenStrcatBoard openBoard={openBoard} />

<div className="flex flex-col items-center justify-center">
<div
className={`pt-[60px] ${bodyFontState.serviceBody} text-center ${defaultState.descriptionText}`}
className={`pt-[56px] ${bodyFontState.serviceBody} text-center ${defaultState.descriptionText}`}
>
내 롤링페이퍼에서 <br /> 친구들의 이야기를 듣고 싶다면
</div>
Expand Down
2 changes: 2 additions & 0 deletions src/component/Common/AxiosInterceptor.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use client';
Copy link
Contributor

Choose a reason for hiding this comment

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

혹시 이부분 추가하신 이유가 있을까요?
이 파일에서 어떤 부분때문에 추가하신 건지 궁금합니다~

Copy link
Contributor Author

Choose a reason for hiding this comment

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

layout 에서 use client를 제거하고 내부 컴포넌트에서 use client를 선언하는 방식으로 변경하게되어 생긴 코드 입니다!


import { useInterceptor } from '@/hooks/useInterceptor';

export default function AxiosInterceptor() {
Expand Down
26 changes: 26 additions & 0 deletions src/component/Common/Icon/PublicBadge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export default function PublicBadge() {
return (
<svg
width="31"
height="22"
viewBox="0 0 31 22"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect
x="0.5"
y="0.5"
width="30"
height="21"
rx="3.5"
fill="white"
fill-opacity="0.2"
/>
<rect x="0.5" y="0.5" width="30" height="21" rx="3.5" stroke="#FDFFB0" />
<path
d="M10.6997 12.3413C11.3908 12.3413 11.9924 12.4111 12.5044 12.5508C13.0164 12.6868 13.4103 12.891 13.686 13.1631C13.9618 13.4316 14.0996 13.7521 14.0996 14.1245C14.0996 14.4897 13.9618 14.8049 13.686 15.0698C13.4103 15.3348 13.0164 15.5389 12.5044 15.6821C11.9924 15.8254 11.3908 15.897 10.6997 15.897C10.0122 15.897 9.41423 15.8254 8.90576 15.6821C8.3973 15.5389 8.00521 15.3348 7.72949 15.0698C7.45378 14.8049 7.31592 14.4897 7.31592 14.1245C7.31592 13.7521 7.45378 13.4316 7.72949 13.1631C8.00521 12.891 8.3973 12.6868 8.90576 12.5508C9.41423 12.4111 10.0122 12.3413 10.6997 12.3413ZM10.6997 13.1094C10.2127 13.1094 9.7902 13.1506 9.43213 13.2329C9.07764 13.3117 8.80371 13.4281 8.61035 13.582C8.42057 13.7324 8.32568 13.9132 8.32568 14.1245C8.32568 14.325 8.42057 14.5005 8.61035 14.6509C8.80371 14.7977 9.07764 14.9105 9.43213 14.9893C9.7902 15.0645 10.2127 15.1021 10.6997 15.1021C11.1903 15.1021 11.6128 15.0645 11.9673 14.9893C12.3254 14.9105 12.6011 14.7977 12.7944 14.6509C12.9878 14.5005 13.0845 14.325 13.0845 14.1245C13.0845 13.9132 12.9878 13.7324 12.7944 13.582C12.6011 13.4281 12.3254 13.3117 11.9673 13.2329C11.6092 13.1506 11.1867 13.1094 10.6997 13.1094ZM13.6001 7.57715H7.39111V6.76074H13.6001V7.57715ZM15.1201 11.541H6.37061V10.7139H15.1201V11.541ZM10.8823 10.9556H9.87793V8.90918H10.8823V10.9556ZM14.0352 7.60938C14.0316 8.12142 14.0137 8.56185 13.9814 8.93066C13.9492 9.2959 13.8758 9.69515 13.7612 10.1284L12.7622 10.0156C12.8696 9.58952 12.9377 9.20459 12.9663 8.86084C12.9985 8.51709 13.0164 8.11426 13.02 7.65234V7.56104V6.76074H14.0352V7.56104V7.60938ZM23.886 15.9077H22.8977V6.28271H23.886V15.9077ZM23.2361 10.9233H21.426V10.0908H23.2361V10.9233ZM19.8039 7.51807C19.8003 8.40967 19.6858 9.23682 19.4602 9.99951C19.2346 10.7622 18.855 11.473 18.3215 12.1318C17.7916 12.7907 17.0862 13.3708 16.2053 13.8721L15.6091 13.1631C16.379 12.7227 17.002 12.2231 17.4782 11.6646C17.9545 11.106 18.2982 10.5008 18.5095 9.84912C18.7208 9.19385 18.8282 8.4777 18.8318 7.70068V7.51807H19.8039ZM19.1487 8.34521H16.0173V7.51807H19.1487V8.34521ZM21.716 15.4512H20.7546V6.54053H21.716V15.4512Z"
fill="#FDFFB0"
/>
</svg>
);
}
2 changes: 2 additions & 0 deletions src/component/InApp.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use client';

import { useEffect } from 'react';

export default function InApp() {
Expand Down
82 changes: 82 additions & 0 deletions src/component/OpenStrcat.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
interface Props {
id: string;
OpenBoardThemeColor: string;
OpenBoardTextColor: string;
theme: string;
contentCount: string;
contentTextCount: string;
title: string;
lastContentCreatedAt: string;
}

export default function OpenStrcat({
id,
OpenBoardThemeColor,
OpenBoardTextColor,
title,
contentCount,
contentTextCount,
lastContentCreatedAt,
}: Props) {
const truncatedTitle = truncateText(title, 19);
const contentText = `${contentCount}개의 마음이, ${contentTextCount}자 이어졌어요!`;
const truncatedContentText = truncateText(contentText, 37);

return (
<div className="flex-none">
<div
className={`flex w-[150px] h-[192px] px-[16px] pt-[20px] pb-[14px] flex-col rounded-[6px] justify-between border-[1px] ${OpenBoardThemeColor}`}
>
<div className="flex flex-col gap-[12px]">
<div className="h-[40px] font-medium leading-5 text-[16px] tracking-[-0.32px] text-white">
{truncatedTitle}
</div>
<div className="h-[80px] font-medium text-[14px] mb-[12px] text-white opacity-70">
{truncatedContentText}
</div>
</div>
<div>
<div className={`text-[12px] text-right ${OpenBoardTextColor}`}>
{timeString(lastContentCreatedAt)}
</div>
</div>
</div>
</div>
);
}

function truncateText(text: string, maxLength: number) {
if (text.length > maxLength) {
return text.substring(0, maxLength - 1) + '...';
}
return text;
}

const timeString = (date: string) => {
const now = new Date();
const lastContentCreatedAt = new Date(date);
const diff = now.getTime() - lastContentCreatedAt.getTime();
const diffSeconds = Math.floor(diff / 1000);
const diffMinutes = Math.floor(diffSeconds / 60);
const diffHours = Math.floor(diffMinutes / 60);
const diffDays = Math.floor(diffHours / 24);
const diffWeeks = Math.floor(diffDays / 7);
const diffMonths = Math.floor(diffDays / 30);
const diffYears = Math.floor(diffMonths / 12);

if (diffSeconds < 11 * 60) {
return '방금';
} else if (diffMinutes < 60) {
return `${diffMinutes}분 전`;
} else if (diffHours < 24) {
return `${diffHours}시간 전`;
} else if (diffDays < 7) {
return `${diffDays}일 전`;
} else if (diffWeeks < 4) {
return `${diffWeeks}주 전`;
} else if (diffMonths < 12) {
return `${diffMonths}개월 전`;
} else {
return `${diffYears}년 전`;
}
};
Loading