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

[SP0] 404, 500 에러페이지 제작 #378

Merged
merged 21 commits into from
Mar 23, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e9d9368
fix: Roundbutton에서 사용하지 않는 isReverse prop 삭제
lydiacho Mar 20, 2024
3e1c365
fix: RoundButton 공통컴포넌트 수정
lydiacho Mar 20, 2024
ca02867
feat: 404 페이지 퍼블리싱
lydiacho Mar 20, 2024
4e9bf13
feat: 에러페이지 에셋 상수화
lydiacho Mar 20, 2024
090fbd3
feat: 에러페이지 라이팅 상수화
lydiacho Mar 20, 2024
919f0ee
feat: 에러코드 상수 분리
lydiacho Mar 20, 2024
35d4b9e
feat: ErrorPage로 404, 500 재사용
lydiacho Mar 20, 2024
4773b42
design: 문의하기 버튼 추가
lydiacho Mar 20, 2024
6881ab1
feat: 문의하기 next/link로 수정 및 링크 연결
lydiacho Mar 20, 2024
7098f14
feat: 에러코드svg 상수파일 -> 컴포넌트로 변경
lydiacho Mar 21, 2024
b9da14c
feat: 에러페이지 assets 반응형 대비
lydiacho Mar 21, 2024
6df42d2
feat: 에러페이지 반응형 작업
lydiacho Mar 21, 2024
778c9d5
feat: 에러코드 컴포넌트 반응형 작업
lydiacho Mar 21, 2024
4b75d5f
chore: 에러코드 Wrapper를 ErrorPage->ErrorCode로 이동
lydiacho Mar 21, 2024
e06df57
feat: 에러페이지 애니메이션 작업
lydiacho Mar 21, 2024
7a357b6
design: 반응형 기준 수정 및 ErrorCode 코드 정리
lydiacho Mar 21, 2024
2cdb9f4
fix: 모바일뷰에서 아이콘 애니메이션 해제
lydiacho Mar 21, 2024
2755c54
fix: 문의하기 버튼 겹치지 않도록 min-height 추가
lydiacho Mar 23, 2024
418429a
fix: ErrorCode 컴포넌트에 쓰이는 스타일 파일 분리
lydiacho Mar 23, 2024
a76cd00
style: code formatter prettier 적용
lydiacho Mar 23, 2024
eecee68
chore: 34기 모집배너 컴포넌트 제거
lydiacho Mar 23, 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
7 changes: 3 additions & 4 deletions src/components/common/RoundButton/RoundButton.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { DetailedHTMLProps, HTMLAttributes, ReactElement } from 'react';
import * as S from './RoundButton.style';
import * as S from './style';

interface ButtonProps
extends DetailedHTMLProps<HTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
children: string | ReactElement;
isReverse?: boolean;
}

function RoundButton({ children, isReverse = false, ...props }: ButtonProps) {
function RoundButton({ children, ...props }: ButtonProps) {
return (
<S.Root isReverse={isReverse} {...props}>
<S.Root type='button' {...props}>
{children}
</S.Root>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import styled from '@emotion/styled';
import { colors } from '@sopt-makers/colors';

interface StyleProps {
isReverse?: boolean;
}

export const Root = styled.button<StyleProps>`
export const Root = styled.button`
display: flex;
align-items: center;

height: 50px;
padding: 10px 30px;
height: 60px;
padding: 12px 28px;
border-radius: 99px;
background: ${colors.gray10};

color: ${colors.gray950};
font-size: 24px;
font-size: 22px;
font-weight: 600;
line-height: 150%; /* 36px */
letter-spacing: -0.48px;
cursor: pointer;

@media (max-width: 428px) {
padding: 8px 22px;
font-size: 18px;
}
`;
50 changes: 2 additions & 48 deletions src/pages/404.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,3 @@
import styled from '@emotion/styled';
import { colors } from '@sopt-makers/colors';
import { useRouter } from 'next/router';
import { Header } from '@src/components';
import RoundButton from '@src/components/common/RoundButton';
import { Page404 } from '@src/views/ErrorPage';

function Wrong() {
const router = useRouter();

const handleButtonClick = () => {
router.push('/');
};

return (
<>
<Header />
<Styled.Root>
<span>잘못된 경로예요</span>
<RoundButton onClick={handleButtonClick} isReverse={true}>
홈으로 가기
</RoundButton>
</Styled.Root>
</>
);
}

export default Wrong;

const Styled = {
Root: styled.section`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 48px;

width: 100%;
height: 100vh;

& span {
color: ${colors.gray10};

font-size: 48px;
font-weight: 600;
line-height: 150%; /* 72px */
letter-spacing: -0.96px;
}
`,
};
export default Page404;
3 changes: 3 additions & 0 deletions src/pages/500.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Page500 } from '@src/views/ErrorPage';

export default Page500;
47 changes: 47 additions & 0 deletions src/views/ErrorPage/ErrorPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { useRouter } from 'next/router';
import { Header } from '@src/components';
import RoundButton from '@src/components/common/RoundButton';
import * as S from './styles';
import ERROR_MESSAGE from './constants/errorMessage';
import ERROR_BUTTON from './constants/errorButton';
import ErrorCode from './components/ErrorCode';

interface ErrorPageProps {
code: 404 | 500;
}

function ErrorPage({ code }: ErrorPageProps) {
const router = useRouter();
const CODE_KEY : 'CODE404' | 'CODE500' = `CODE${code}`;

const handleButtonClick = () => {
code===404? router.push('/') : router.back();
};

return (
<>
<Header />
<S.Root>
<S.TopSection>
<ErrorCode code={code}/>
Copy link
Member

@eonseok-jeon eonseok-jeon Mar 23, 2024

Choose a reason for hiding this comment

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

혹시 prettier가 적용이 안 되나요?
ErrorCode에 space가 2칸 더 들어가 있네용~

<S.ErrorText>{ERROR_MESSAGE[CODE_KEY]}</S.ErrorText>
<RoundButton onClick={handleButtonClick}>
{ERROR_BUTTON[CODE_KEY]}
</RoundButton>
</S.TopSection>
{code === 500 && (
<S.ContactLink
href="https://walla.my/sopt_official"
target="_blank"
rel="noopener noreferrer"
>
문의하기
</S.ContactLink>
)}
</S.Root>
</>
);
}

export const Page404 = () => <ErrorPage code={404} />;
export const Page500 = () => <ErrorPage code={500} />;
4 changes: 4 additions & 0 deletions src/views/ErrorPage/assets/ic_404_back.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/views/ErrorPage/assets/ic_404_front.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/views/ErrorPage/assets/ic_404_ghost.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/views/ErrorPage/assets/ic_404_ghost_dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/views/ErrorPage/assets/ic_500_back.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/views/ErrorPage/assets/ic_500_cone.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/views/ErrorPage/assets/ic_500_cone_dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/views/ErrorPage/assets/ic_500_front.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions src/views/ErrorPage/assets/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ReactComponent as Ic404Front } from './ic_404_front.svg';
import { ReactComponent as Ic404Back } from './ic_404_back.svg';
import { ReactComponent as Ic404Ghost } from './ic_404_ghost.svg';
import { ReactComponent as Ic404GhostDark } from './ic_404_ghost_dark.svg';
import { ReactComponent as Ic500Front } from './ic_500_front.svg';
import { ReactComponent as Ic500Back } from './ic_500_back.svg';
import { ReactComponent as Ic500Cone } from './ic_500_cone.svg';
import { ReactComponent as Ic500ConeDark } from './ic_500_cone_dark.svg';

export { Ic404Front, Ic404Back, Ic404Ghost, Ic404GhostDark, Ic500Cone, Ic500Back, Ic500Front, Ic500ConeDark };
64 changes: 64 additions & 0 deletions src/views/ErrorPage/components/ErrorCode.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { useIsMobile } from '@src/hooks/useDevice';
import { Ic404Back, Ic404Front, Ic404Ghost, Ic404GhostDark, Ic500Back, Ic500Cone, Ic500ConeDark, Ic500Front } from '../assets';
import * as S from '../styles';

interface ErrorCodeProps {
code: 404 | 500;
}
export default function ErrorCode({ code }: ErrorCodeProps) {
const isMobile = useIsMobile('428px');
Copy link
Member Author

Choose a reason for hiding this comment

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

모바일 뷰를 대응해야 하는데 다른 컴포넌트들 처럼 css로 스타일링하는게 아닌 svg 컴포넌트를 조건부로 렌더링해야 하는 케이스이기 때문에 media-query를 사용하기 부적절해서 기존에 만들어져있던 공통 훅인 useDevice를 활용해보았습니당

useIsMobile 안에 브레이크포인트를 넣어주면 isMobile boolean 값으로 브레이크포인트 이상 / 이하에 따라 조건부 렌더링을 해줄 수 있어요!

const SIZE = {
height: 92,
icon: 150,
};
Comment on lines +19 to +22
Copy link
Member Author

Choose a reason for hiding this comment

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

이친구들은 굳이 왜 상수화를 했냐... 하는 의문이 드실텐데

기존에는 768px 이상 / 이하에 따라 모든 svg들의 크기를 조절해야했어요.
그러기 위해 모든 svg 파일 내부에 width, height 값을 지워주고 viewBox만 남겨놓고 (width, height 안지워주면 직접 설정해줄 경우 아이콘이 축소되는게 아니라 잘리게 됨)
이곳에서 svg 불러올때 width, height 값을 반응형에 따라 설정해주려고 이렇게 따로 분리시켜놨었어요

근데 이후에 모바일뷰를 제외하고는 아이콘 사이즈를 모두 통일하는 것으로 디자인이 바뀌어서
쓸모없어졌지만,, 추후 브레이크 포인트가 추가될 가능성을 열어놓고 그냥 냅두었습니다

해당 커밋 보시면 isTablet 값에 따라 사이즈를 조정해준 방식 확인하실 수 있습니다 !


const codeVariant = {
initial: { gap: '6px' },
whileHover: { gap: '159px' },
};

const iconVariant = {
initial: { opacity: 0 },
whileHover: { opacity: 1 },
};

const animationProps = {
initial : 'initial',
whileHover : 'whileHover',
transition : { duration: 0.3 },
};

return (
<S.ErrorCode {...animationProps} variants={codeVariant}>
{code === 404 ? (
<>
{!isMobile &&
<>
<Ic404Front height={SIZE.height} />
<Ic404Back height={SIZE.height} />
</>
}
{isMobile ? <Ic404GhostDark /> :
<S.ErrorIcon {...animationProps} variants={iconVariant}>
<Ic404Ghost height={SIZE.icon} />
</S.ErrorIcon>
}
</>
) : (
<>
{!isMobile &&
<>
<Ic500Front height={SIZE.height} />
<Ic500Back height={SIZE.height} />
</>
}
{isMobile ? <Ic500ConeDark /> :
<S.ErrorIcon {...animationProps} variants={iconVariant}>
<Ic500Cone height={SIZE.icon} />
</S.ErrorIcon>
}
</>
)}
</S.ErrorCode>
);
}
6 changes: 6 additions & 0 deletions src/views/ErrorPage/constants/errorButton.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const ERROR_BUTTON = {
CODE404 : '홈으로 가기',
CODE500 : '이전 페이지로 가기',
};

export default ERROR_BUTTON;
6 changes: 6 additions & 0 deletions src/views/ErrorPage/constants/errorMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const ERROR_MESSAGE = {
CODE404 : '존재하지 않는 페이지예요',
CODE500 : '알 수 없는 오류가 발생했어요',
};

export default ERROR_MESSAGE;
3 changes: 3 additions & 0 deletions src/views/ErrorPage/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Page404, Page500 } from './ErrorPage';

export { Page404, Page500 };
62 changes: 62 additions & 0 deletions src/views/ErrorPage/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import styled from '@emotion/styled';
import { motion } from 'framer-motion';
import Link from 'next/link';

export const Root = styled.main`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;

position: relative;

width: 100%;
height: 100vh;
padding-bottom: 20vh;
`;
export const TopSection = styled.section`
display: flex;
flex-direction: column;
align-items: center;
gap: 34px;

width: 100%;
`;
export const ErrorText = styled.p`
color: #FCFCFC;

font-size: calc(24px + 1vw);
font-weight: 600;
line-height: 150%;
letter-spacing: -0.96px;
`;
export const ContactLink = styled(Link)`
position: fixed;
bottom: 17vh;

Copy link
Member

@eonseok-jeon eonseok-jeon Mar 23, 2024

Choose a reason for hiding this comment

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

스크린샷 2024-03-23 오후 2 16 19

bottom: 17vh 이렇게 하니까
웹 창 크기가 작아지면 사진처럼 텍스트가 겹치게 되네요

이전 페이지로 가기 버튼과 문의하기 사이 gap이나 margin 등을 주거나 길이 고정하고 스크롤 생기게 하는 등으로 그 둘 사이가 겹치지 않게 해주면 좋을 거 같아요~

Copy link
Member Author

Choose a reason for hiding this comment

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

두 콘텐츠 사이의 gap을 잡아주는 것이 아닌, 위 아래 마진을 기준으로 콘텐츠를 배치했던 것은 디자이너분께서 요청주신 부분이었습니다!! 그래서 bottom 값을 pixel 값이 아닌 viewheight 비율로 주어 최대한 문의하기 버튼이 겹칠 가능성을 줄이는 것 정도로 타협을 봤었습니다 ㅎ ㅎ

모쪼록 저도 찝찝했던 부분이라 해당 부분

  • 문의하기 버튼 position: fixed -> absolute (최상위 Wrapper에 종속되도록)
  • 최상위 Wrapper에 min-height 추가 (문의하기 버튼이 겹치기 직전 값으로)
  • 최상위 Wrapper에 overflow : scroll 추가

요 방법으로 대응했습니다! 👍

color: #FFF;
font-size: 24px;
font-weight: 600;
line-height: 150%; /* 36px */
letter-spacing: -0.48px;
text-decoration-line: underline;

cursor: pointer;

@media (max-width: 428px) {
font-size: 18px;
}
`;
export const ErrorCode = styled(motion.div)`
display: flex;
align-items: center;
gap: 6px;

position: relative;
`;
export const ErrorIcon = styled(motion.div)`
display: flex;
justify-content: center;
position: absolute;
width: 100%;
`;
Copy link
Member

Choose a reason for hiding this comment

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

ErrorCode.tsx에서 사용되는 css 코드인 거 같은데 여기에 넣으신 이유가 따로 있으실까요?
기존의 다른 component 요소들을 보니 각각의 style.ts를 가지고 있는 거 같아서요

Copy link
Member Author

Choose a reason for hiding this comment

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

너무 작은 컴포넌트를 위한 스타일 파일을 별도로 만들어주기 싫고, 그렇다고 한 파일 내에 스타일을 정의해주고 싶지는 않아서 선택한 방식인데, 일관성을 위해 기존의 컨벤션에 맞춰서 파일분리하겠습니다!

오프라인으로 논의한 것처럼 컴포넌트명.style.ts 파일 생성해서 분리해주겠습니다 👍

Loading