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

[Feat] 35기 YB 리크루팅 페이지 업데이트 #407

Merged
merged 11 commits into from
Sep 4, 2024
7,508 changes: 4,184 additions & 3,324 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

Binary file added src/assets/images/img_recruit_banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 4 additions & 2 deletions src/assets/mainLogo/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import imgLogoSopt from './img_logo_sopt.png';
import logo11 from './logo_11.svg';
import logo12 from './logo_12.svg';
import logo14 from './logo_14.svg';
Expand All @@ -18,11 +19,12 @@ import logo28 from './logo_28.svg';
import logo29 from './logo_29.svg';
import logo30 from './logo_30.svg';
import logo31 from './logo_31.svg';
import logoAndSoptDark from './logo_andsopt_dark.png';
import logoDoSopt from './logo_dosopt@3x.png';
import imgLogoSopt from './img_logo_sopt.png';
import logoNowSopt from './logo_nowsopt.png';

export {
imgLogoSopt,
logo11,
logo12,
logo14,
Expand All @@ -43,7 +45,7 @@ export {
logo29,
logo30,
logo31,
logoAndSoptDark,
logoDoSopt,
imgLogoSopt,
logoNowSopt,
};
Binary file added src/assets/mainLogo/logo_andsopt_dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/Header/constants/menuTapList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ export const menuTapList: MenuTapList = [
{
type: MenuTapType.SPECIAL,
title: '지원하기',
href: 'https://recruit.sopt.org/',
href: '/recruit',
},
];
15 changes: 0 additions & 15 deletions src/hooks/useCheckTime.ts

This file was deleted.

14 changes: 14 additions & 0 deletions src/hooks/useTimeInRange.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useEffect, useState } from 'react';

export default function useTimeInRange(startDate: string, endDate: string) {
const start = new Date(startDate).getTime();
const end = new Date(endDate).getTime();

const [isValid, setIsValid] = useState(Date.now() >= start && Date.now() <= end);

useEffect(() => {
setIsValid(Date.now() >= start && Date.now() <= end);
}, [start, end]);
Copy link
Member

Choose a reason for hiding this comment

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

뒷북이긴 한데 사실 useEffect 사용 안 해도 될 거 같아요!

처음 useTimeInRange가 실행되면 isValid가 Date.now() >= start && Date.now() <= end 로 초기화 되기 때문에 useEffect를 이용해서 한 번 더 set 해줄 필요는 없어 보여요~

Copy link
Contributor Author

Choose a reason for hiding this comment

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

그렇긴 하네요 ! 사실 prop이 변경되었을 때 또한 트리거하기 위해서 useEffect를 사용한건데, 언석님 말씀대로 지원 시작 기간과 종료기간을 상태가 아닌 그냥 상수로 넣어줄거라면 필요가 없을 것 같긴 합니다 !

만약 useEffect를 제외할거라면 해당 커스텀 훅을 그냥 삭제시키고 사용하는 쪽에서 다 적어주어도 무방할거 같다고 생각하는데, 다들 어떻게 생각하시나용

Copy link
Member

Choose a reason for hiding this comment

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

그렇게 해도 무방하겠지만 저의 의견을 짧게 말씀드리자면,,,

해당 동일 로직이 Main page와 Recruit Page 둘 다에서 사용되고 있기에,
각 페이지 컴포넌트에서 로직을 분리하여 custom hook으로 관리하고 또 해당 hook을 재사용할 수 있단 측면에서
큰 기능이 없다 하더라도 custom hook으로 분리하여 관리하는 것이 더 깔끔할 거 같단 생각입니다!

하지만 아직까진 두 군데서 밖에 쓰이지 않고 추후에도 어딘가 이를 이용할 곳이 더 생기진 않을 거 같아 주용님 편하신 대로 해도 좋습니다~~~~

Copy link
Contributor Author

Choose a reason for hiding this comment

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

그렇다면 숭희만 어푸하면 이대로 머지하겠슴니당

Copy link
Member

@eonseok-jeon eonseok-jeon Sep 4, 2024

Choose a reason for hiding this comment

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

아 useEffect는 빼고 말한 거였어요!
useEffect 제외한 나머지 부분을 hook으로 그대로 유지한 채 사용이었습니다!!
제가 아까부터 계속 표현을 모호하게 한 거 같네요ㅜ 좀 더 확실하게 표현하도록 노력해볼게요!! 😅

Copy link
Member

@eonseok-jeon eonseok-jeon Sep 4, 2024

Choose a reason for hiding this comment

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

첫 렌더링 시 setter 함수에서 초기화 된 값과 동일한 값을 useEffect에서 다시 set 해주는 건데 어떤 면에서 사용자 측면에 유연한 건지 조금 잘 모르겠어요ㅜ useEffect를 넣음으로써 어떻게 유연성이 확장이 되는 지 좀 더 설명해 주실 수 있으신가요???

Copy link
Member

@lydiacho lydiacho Sep 4, 2024

Choose a reason for hiding this comment

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

음 그런데용
현재 저희가 결정한대로면 사용자의 리로드에 의존해서 해당 훅이 실행됐을 때 isValid한 시간인지 체크하기로 했잖아용
그럼 useEffect 뿐만 아니라 useState도 그냥 싸그리 없애버려도 되는거 아닌가요?


현재 저희 코드가

export default function useTimeInRange(startDate: string, endDate: string) {
  const start = new Date(startDate).getTime();
  const end = new Date(endDate).getTime();
  const [isValid, setIsValid] = useState(Date.now() >= start && Date.now() <= end);

  useEffect(() => {
    setIsValid(Date.now() >= start && Date.now() <= end);
  }, [start, end]);

  return isValid;
}

이렇게 생겼는데

  • 언석님이 말씀하시는대로 현재 useTimeInRange의 props가 startDate, endDate 이기 때문에 해당 값들이 바뀌면 알아서 useTimeInRange는 재실행될거고 (어차피 상수라 그럴일없겠지만)
  • start, end 값은 startDate, endDate에서 나온 애들이니까 useEffect에서 의존성배열로 체킹해줄 필요 없고
  • 타이머 체크 안하고 리로드하기로 했으니까 isValid 여부를 체크해서 동적으로 렌더링시켜줄 필요도 없어진거 같아요

즉 얘가 해줄 일은 단순히

시작일시, 마감일시를 입력했을 때, 실행 시 valid한 시간인지 뱉어주기

이거 밖에 안하게될 것 같아요


그래서 싸그리 빼버리고

const checkTimeInRange = (startDate: string, endDate: string) =>
  Date.now() >= new Date(startDate).getTime() && Date.now() <= new Date(endDate).getTime();

이렇게 valid한 날짜인지 boolean으로 뱉어주는 간단한 유틸함수로 바꿔주는게 낫지 않을까유?

Copy link
Member

@eonseok-jeon eonseok-jeon Sep 4, 2024

Choose a reason for hiding this comment

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

@lydiacho 오홍? 그것도 그렇네요!? 제 시야가 너무 좁게 잡혔던 거 같아여 😓 좋은 거 같습니다~~

Copy link
Contributor Author

Choose a reason for hiding this comment

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

두분 말씀 다 이해했습니다. 저 또한 생각이 좀 짧았던 것 같네요.

  1. 저는 일단 인자가 상태 값으로 변경되었을 시에도 값을 최신화하고 싶었던 생각이였는데, 어차피 해당 커스텀 훅 소비자의 상태가 바뀐다면 해당 커스텀 훅도 재실행될테니 useEffect도 필요가 없어질 것 같아요. 그렇다면 Date에 의한 isValid도 최신화가 되겠네요
  2. 따라서 승희 말대로 어차피 리로드에 의존할 것이므로 상태로 작성해줄 필요도 없겠네요.

이해 완료했습니다 ~ 피드백 감사드려요.

그럼 최종 방향대로 유틸 함수로 작성해서 다시 반영할까요 ?

Copy link
Member

@lydiacho lydiacho Sep 4, 2024

Choose a reason for hiding this comment

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

네네 좋습니두 유틸함수 반영된거 보이면 바로 어푸 날릴게여 ! ! !
고생하셨습니당 ~~


return isValid;
}
4 changes: 2 additions & 2 deletions src/views/MainPage/components/Banner/index.tsx
Copy link
Member

Choose a reason for hiding this comment

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

34기 YB 지원하기 -> 35기 YB 모집하기로 바꾸면 좋을 거 같아요 :)

Copy link
Member

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.

넵 메인페이지 작업할 때 처리할 것이였어서 그 때 반영하겠습니다 !

Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import imgMainPageBanner from '@src/assets/images/img_mainBanner.png';
import useCheckTime from '@src/hooks/useCheckTime';
import useTimeInRange from '@src/hooks/useTimeInRange';
import RecruitButton from './RecruitButton';
import * as S from './style';

export default function Banner() {
const isValid = useCheckTime(); // 모집 여부
const isValid = useTimeInRange('2024-09-08 10:00:00', '2024-09-13 18:00:00'); // 모집 여부

const onScrollMoveDown = () => {
const element = document.getElementById('nextContainer');
Expand Down
17 changes: 6 additions & 11 deletions src/views/RecruitPage/components/ApplySection/index.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import imgRecruitBg from '@src/assets/images/img_recruit_bg.png';
import imgRecruitBg from '@src/assets/images/img_recruit_banner.png';
import * as S from './style';
import { ReactComponent as ValueShare } from '@src/assets/icons/value_share.svg';
import { ReactComponent as ValueChallenge } from '@src/assets/icons/value_challenge.svg';
import { ReactComponent as ValueLink } from '@src/assets/icons/value_link.svg';

const ApplySection = () => {
return (
<S.Wrapper imgRecruitBg={imgRecruitBg}>
<S.Values>
<ValueShare/>
<ValueChallenge/>
<ValueLink/>
</S.Values>
<S.Title><span>SOPT의 34번째 열정을&nbsp;</span><span>기다리고 있어요!</span></S.Title>
<S.ApplyButton href="https://sopt-recruiting.web.app/recruiting/application/yb" target="_blank">
<S.Title>
<span>SOPT의 35번째 열정을&nbsp;</span>
<span>기다리고 있어요!</span>
</S.Title>
<S.ApplyButton href="https://recruit.sopt.org/" target="_blank">
지원하기
</S.ApplyButton>
</S.Wrapper>
Expand Down
30 changes: 3 additions & 27 deletions src/views/RecruitPage/components/ApplySection/style.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,6 @@
import styled from '@emotion/styled';
import { StaticImageData } from 'next/image';

export const Values = styled.div`
display: flex;
justify-content: center;
gap: 90px;

& > svg {
transform: scale(2);
}

/* 태블릿 뷰 */
@media (max-width: 81.1875rem) and (min-width: 47.875rem) {
gap: 21px;
& > svg {
transform: scale(1);
}
}
/* 모바일 뷰 */
@media (max-width: 47.86875rem) {
gap: 18px;
& > svg {
transform: scale(1);
}
}
`;

export const ApplyButton = styled.a`
width: 220px;
padding: 24px 0;
Expand All @@ -37,7 +12,7 @@ export const ApplyButton = styled.a`
font-weight: 700;
line-height: 100%; /* 22px */
letter-spacing: -0.44px;
background-color: #bdec00;
background-color: #5ba3ff;
z-index: 2;
/* 태블릿 뷰 */
@media (max-width: 81.1875rem) and (min-width: 47.875rem) {
Expand Down Expand Up @@ -97,11 +72,12 @@ export const Wrapper = styled.div<{ imgRecruitBg: StaticImageData }>`

/* 태블릿 뷰 */
@media (max-width: 81.1875rem) and (min-width: 47.875rem) {
height: 400px;
height: 302px;
}
/* 모바일 뷰 */
@media (max-width: 47.86875rem) {
margin-top: 48px;
font-size: 28rem;
height: 409px;
}
`;
13 changes: 10 additions & 3 deletions src/views/RecruitPage/components/BottomLogo/index.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import styled from '@emotion/styled';
import Image from 'next/image';
import { logoNowSopt } from '@src/assets/mainLogo';
import { logoAndSoptDark } from '@src/assets/mainLogo';

const BottomLogo = () => {
return <ScaledImage src={logoNowSopt} alt="34기 솝트 로고" />;
return <ScaledImage src={logoAndSoptDark} alt="35기 솝트 로고" />;
};

const ScaledImage = styled(Image)`
width: 362px;
height: auto;
margin-top: 338px;
margin-bottom: 86px;

/* 태블릿 뷰 */
@media (max-width: 81.1875rem) and (min-width: 47.875rem) {
width: 209px;
height: 25px;
}
/* 모바일 뷰 */
@media (max-width: 47.86875rem) {
width: 276px;
width: 138px;
height: 16px;
}
`;

Expand Down
58 changes: 29 additions & 29 deletions src/views/RecruitPage/components/ChapterInfo/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,56 @@ import { Part } from '@src/lib/types/universal';

export const infoMap: Record<Part, { info: string; fit: string[] }> = {
[Part.PLAN]: {
info: '린스타트업에 기초해 고객 문제정의 - 고객 발굴 - 검증 과정을 거쳐 비즈니스 전략과 핵심지표 설계까지 고객 관점 프로덕트를 만들고 운영하기 위한 모든 과정을 다룹니다.',
info: '고객 시장 탐색부터 프로덕트 설계와 운영까지, 더블 다이아몬드 프로세스를 이용하여 더욱 탄탄한 프로덕트를 설계해볼 수 있습니다.',
fit: [
'열정과 책임감을 가지고 기획에 진심으로 임할 분',
'본인이 가진 지식과 경험을 아낌없이 공유하고, 원활한 소통을 위한 열려있는 마음과 자세를 가진 분',
'본인에게 한계를 두지 않고 앞으로 나아가는 용기와 도전하는 자세를 가진 분',
'본인이 가진 열정과 의지가 행동으로 드러나는 분',
'어려움과 고민을 편하게 나누고 공감할 수 있는 유대감과 열린 마음을 가진 분',
'타 파트와 협업하며 존중과 신뢰를 바탕으로 원활한 팀워크를 만들어갈 수 있는 분',
'도전과 성장의 자세로 한계를 두지 않고 앞으로 나아가고자 하는 열정이 있는 분',
'본인이 가진 지식과 경험을 아낌없이 공유하고, 책임감을 가지고 팀 활동에 임할 수 있는 분',
],
},
[Part.DESIGN]: {
info: 'Figma를 활용하여 UX/UI 디자인의 전반적인 프로세스를 배우고, 세미나에서 학습한 UX심리학, 브랜딩, 디자인 시스템 등의 이론을 기획자, 개발자와의 협업 과정에 적용해 보며 근거에 기반한 문제 해결을 경험합니다.',
info: 'UX 설계, UI, GUI, 브랜딩, 인터랙션 디자인 등 프로덕트 디자인의 전 과정을 학습하며 기획자, 개발자와의 체계적인 협업 방식을 통해 문제의 근원을 주도적으로 해결합니다.',
fit: [
'자신의 디자인적 관점과 경험을 공유하며 함께 성장하실 수 있으신 분',
'사용자의 경험에 기반한 UXUI디자인에 대해 고민해 보신 분',
'타인의 피드백을 두려워하지 않고 새로운 것을 시도하며 도전적인 자세로 임하실 분',
'사람들과 유대관계를 형성하는 것을 즐길 줄 아시는 분',
'사용자 관점에서 프로덕트를 설계한 경험이 있으신 분',
'원활한 커뮤니케이션을 위해 수용적 태도를 지니고 계신 분',
'자신의 경험을 공유하는 것을 즐기고 팀원들과의 상호 성장에서 오는 기쁨을 아시는 분',
'화합의 가치를 알고 중요시하며 네트워킹을 즐기시는 분',
],
},
[Part.ANDROID]: {
info: 'Kotlin 언어를 활용해 안드로이드 UI(XML/Compose) 구현 기초/심화, 서버 통신 등 앱 제작에 필요한 내용들을 배웁니다. 세미나, 정규 미미나를 통해 다양한 문제 상황을 해결할 수 있는 역량을 기르며 타 파트와의 협업을 통해 직접 서비스를 제작하는 경험을 얻을 수 있습니다.',
info: 'Kotlin을 활용해 UI 구현 서버 통신 등 안드로이드 개발에 대한 전반적인 지식을 학습하며, 기획, 디자인, 서버 파트와의 협업을 통해 열정이 담긴 IT 서비스를 출시하는 경험을 수 있습니다.',
fit: [
'어려운 상황에도 두려움 없이 도전하며, 자신이 맡은 역할에 대한 책임감을 갖고 행동하는 분',
'자신의 지식과 경험을 공유하고, 이를 통해 파트원들에게 긍정적인 영향을 미칠 수 있는 분',
'상호간의 신뢰와 존중을 바탕으로 함께 목표를 달성하기 위해 협력하는 분',
'같이의 가치를 알고 함께 도전하며 성장하실 수 있으신 분',
'주어진 일에 책임을 다하기 위해서 끊임없이 노력하시는 분',
'자신의 지식과 경험 아낌없이 나누며 타인에게 긍정적인 영향을 미치는 분',
'존중과 배려를 바탕으로 사람들과 소통하며 협업할 줄 아시는 분',
],
},
[Part.IOS]: {
info: 'Swift와 UI Kit를 이용해 iOS 앱 서비스를 만들 수 있습니다. iOS가 처음인 분들을 위한왕초보 스터디와 보충 세미나, 실력적 도약을 위한 심화 세미나까지 존재합니다.',
info: 'UIKit & SwiftUI를 활용한 앱 개발을 진행하며 본인의 프로젝트를 직접 기획하고 개발하는 경험을 얻습니다.',
fit: [
'부족함을 성장의 기회로 느끼며, 열정을 겸비하여 용기있게 도전할 수 있으신 분',
'같이의 가치를 중요시하며, 팀의 성장을 위해 아낌없이 공유할 수 있으신 분',
'할 땐 하고, 놀 땐 그 누구보다 신나게 놀 수 있으신 분',
'세상이 필요하는 서비스를 제공하기 위해 끊임없이 연구하는 Problem Solver의 자세를 가지신 분',
'진심으로 도전하는 마음가짐과 그에 대한 근거가 있으신 분',
'폭발적인 성장 가능성을 가지고 계신 분',
'원활한 커뮤니케이션이 가능하신 분',
'프로덕트에 대한 관심이 많으신 분',
],
},
[Part.WEB]: {
info: 'HTML, CSS, JavaScript로 기초를 다지고 React를 활용해 UI구현, 서버 통신, 다양한 라이브러리 사용 등 웹 서비스 개발에 필요한 역량들을 기초부터 심화까지 학습합니다. 또한 기획자, 디자이너, 서버 개발자와의 협업을 통해 나만의 웹 서비스를 만드는 경험을 해보실 수 있습니다.',
info: 'React를 활용한 웹 서비스 개발을 기초부터 심화까지 학습하며, 협업 과정에서는 기획자, 디자이너, 서버 개발자와의 원활한 소통 방법을 배웁니다. 이를 통해 최종적으로 자신만의 웹 서비스를 출시하는 것을 목표로 합니다.',
fit: [
'웹 프론트엔드 개발에 대한 확실한 목표를 가지고 노력해오신 분',
'적극적이고 활발하게 SOPT와 웹 파트에 참여하실 분',
'상호성장하는 기쁨과 공유의 가치를 아시는 분',
'웹 파트에서 함께 공부하고 즐기며 소속감과 애착을 가지고 싶으신 분',
'웹 프론트엔드 개발에 관심을 가지고 명확한 목표와 함께 꾸준히 노력하시는 분',
'지식과 경험을 공유하며 상호 성장의 가치를 알고, 함께 성장하고 싶으신 분',
'적극적이고 활발하게 SOPT와 웹 파트 활동에 참여하실 분',
'팀워크를 중요시하며 다른 파트원들과의 협업을 통해 성과를 이루고 싶으신 분',
],
},
[Part.SERVER]: {
info: '세미나를 통해 Spring 프레임워크, 관계형 데이터베이스, AWS, Docker를 기반으로 실제 서비스를 위한 서버 구축의 전반적인 내용을 배웁니다.또한 스터디와 코드리뷰, 미니 세미나를 등 개발 실력의 도약과 기획파트, 디자인파트, 클라이언트 파트와 협업을 통해 협업 방식을 익힐 수 있습니다.',
info: '설계와 의사소통을 배우며, Spring framework 로 application 을 구현합니다.',
fit: [
'새로운 도전을 추구하며 이뤄가는 과정의 소중함을 아시는분',
'뜨거운 열정을 불태워 회원들과 함께 성장할 준비가 되어있으신 분',
'공부한 지식과 경험을 공유하며 유대를 통해 성장하는 경험을 만들어가고 싶으신 분',
'목적의식을 가지고 서버파트에서 새로운 목표를 이뤄나가고 싶으신 분',
'어려워도 끝까지 파내실분',
'다른 분들이 뒤쳐지지않도록 도움을 줄 수 있는 분',
'소통이 매끄럽고, 분위기를 즐길수 있는 분',
],
},
};
11 changes: 6 additions & 5 deletions src/views/RecruitPage/components/ChapterInfo/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const BlueChip = styled(BaseChip)`
`;

const GreenChip = styled(BaseChip)`
color: #bdec00;
color: #5ba3ff;
padding-left: 20px;
&:before {
content: '👍';
Expand Down Expand Up @@ -73,6 +73,7 @@ const InfoWrapper = styled(BaseText)`
padding: 45px 80px;
font-weight: 600;
line-height: 42px;
width: 100%;

/* 태블릿 뷰 */
@media (max-width: 81.1875rem) and (min-width: 47.875rem) {
Expand All @@ -92,7 +93,7 @@ const InfoWrapper = styled(BaseText)`

const FitWrapper = styled(BaseText)`
border-radius: 30px;
background: #21270f;
background: #1c2837;
padding: 60px 80px;
display: flex;
flex-direction: column;
Expand Down Expand Up @@ -152,10 +153,10 @@ export {
BaseChip,
BaseText,
BlueChip,
GreenChip,
Container,
FitWrapper,
GreenChip,
InfoWrapper,
Wrapper,
Container,
SectionWrapper,
Wrapper,
};
4 changes: 2 additions & 2 deletions src/views/RecruitPage/components/FAQ/QuestionBox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const Styled = {
color: #ffffff;
&::before {
content: 'Q. ';
color: #bdec00;
color: #5ba3ff;
}

/* 모바일 뷰 */
Expand Down Expand Up @@ -101,7 +101,7 @@ const Styled = {

&::before {
content: 'A. ';
color: #bdec00;
color: #5ba3ff;
}
/* 태블릿 뷰 */
@media (max-width: 119.99375rem) and (min-width: 47.875rem) {
Expand Down
Loading
Loading