diff --git a/src/components/Footer/OriginFooter/style.ts b/src/components/Footer/OriginFooter/style.ts
index 68447727..6ae09bc7 100644
--- a/src/components/Footer/OriginFooter/style.ts
+++ b/src/components/Footer/OriginFooter/style.ts
@@ -4,7 +4,7 @@ import { colors } from '@sopt-makers/colors';
export const Root = styled.footer`
width: 100%;
min-height: 162px;
- background-color: #2a2a2a;
+ background-color: ${colors.gray800};
/* 태블릿 + 데스크탑 뷰 */
@media (min-width: 766px) {
diff --git a/src/components/Header/Desktop/DesktopHeader.tsx b/src/components/Header/Desktop/DesktopHeader.tsx
index f996103f..42e7c09a 100644
--- a/src/components/Header/Desktop/DesktopHeader.tsx
+++ b/src/components/Header/Desktop/DesktopHeader.tsx
@@ -1,16 +1,15 @@
import styled from '@emotion/styled';
+import { colors } from '@sopt-makers/colors';
import Link from 'next/link';
import { css } from '@emotion/react';
-import { useCallback, useEffect, useState } from 'react';
import { LOGO_IMAGE_URL } from '@src/assets/mainLogo/base64_logo';
import useHeader from '@src/hooks/useHeader';
import { GrowDown } from '@src/lib/styles/animation';
import { menuTapList } from '../menuTapList';
-import { BaseMenuTap, MenuTapType, ParentMenuTap } from '../types';
+import { MenuTapType, SingleMenuTap } from '../types';
function DesktopHeader() {
const { handleClickLogo, handleIsSelected } = useHeader();
- const [isSubTapOpened, setIsSubTapOpened] = useState(false);
return (
<>
@@ -20,147 +19,44 @@ function DesktopHeader() {
{menuTapList.map((menuTap) => (
-
+
))}
- {isSubTapOpened && }
>
);
}
type MenuTapProps = {
- menuTap: BaseMenuTap;
+ menuTap: SingleMenuTap;
handleIsSelected: (path: string | string[]) => boolean;
- isSubTapOpened: boolean;
- setIsSubTapOpened: (isOpened: boolean) => void;
};
-function MenuTap({ menuTap, handleIsSelected, isSubTapOpened, setIsSubTapOpened }: MenuTapProps) {
+function MenuTap({ menuTap, handleIsSelected }: MenuTapProps) {
switch (menuTap.type) {
case MenuTapType.Anchor:
return (
- setIsSubTapOpened(false)}
- onMouseEnter={() => setIsSubTapOpened(false)}
- >
+
{menuTap.title}
);
case MenuTapType.Router:
return (
- setIsSubTapOpened(false)}
- onMouseEnter={() => setIsSubTapOpened(false)}
- >
+
{menuTap.title}
);
- case MenuTapType.Parent:
- return (
-
- );
}
}
-type ParentMenuProps = {
- menuTap: ParentMenuTap;
- handleIsSelected: (path: string | string[]) => boolean;
- isSubTapOpened: boolean;
- setIsSubTapOpened: (isOpened: boolean) => void;
-};
-
-function ParentMenu({
- menuTap,
- handleIsSelected,
- isSubTapOpened,
- setIsSubTapOpened,
-}: ParentMenuProps) {
- const [isOpened, setIsOpened] = useState(false);
-
- const closeSubTap = useCallback(() => {
- setIsSubTapOpened(false);
- setIsOpened(false);
- }, [setIsSubTapOpened, setIsOpened]);
-
- const onMouseIn = () => {
- setIsSubTapOpened(true);
- setIsOpened(true);
- };
-
- useEffect(() => {
- if (!isSubTapOpened) {
- setIsOpened(false);
- }
- }, [isSubTapOpened]);
-
- useEffect(() => {
- if (isSubTapOpened) {
- document.addEventListener('click', closeSubTap);
- }
- return () => {
- document.removeEventListener('click', closeSubTap);
- };
- }, [closeSubTap, isSubTapOpened]);
-
- return (
- t.href))}
- isOpened={isOpened}
- onMouseEnter={onMouseIn}
- onClick={(e) => e.stopPropagation()}
- >
- {menuTap.title}
- {isOpened && (
-
- {menuTap.children.map((c) => {
- switch (c.type) {
- case MenuTapType.Anchor:
- return (
-
-
- {c.title}
-
-
- );
- case MenuTapType.Router:
- return (
-
- {c.title}
-
- );
- }
- })}
-
- )}
-
- );
-}
-
interface MenuTitleProps {
isSelected?: boolean;
isOpened?: boolean;
- type?: 'main' | 'sub';
}
export const Wrapper = styled.div`
- max-width: 1280px;
- width: 90%;
+ max-width: 1200px;
+ width: 100%;
display: flex;
justify-content: space-between;
`;
@@ -175,21 +71,6 @@ export const SubMenuWrapper = styled.div`
animation: growdown 0.4s forwards;
`;
-const SubMenu = styled.div`
- position: absolute;
- z-index: 1;
- display: flex;
- align-items: center;
- justify-content: center;
-
- width: 300px;
- top: 80px;
- left: 25%; /* it is bad practice */
- transform: translateX(-50%);
-
- cursor: default;
-`;
-
export const CenterAligner = styled.div`
display: flex;
align-items: center;
@@ -234,46 +115,35 @@ export const MenuTitleAnchor = styled(Link)`
}
`;
-const menuTitleUnderline = css`
- &::after {
- content: '';
- position: absolute;
- top: 3.5rem; /* this is bad practice */
- left: -20px;
- width: 100%;
- border-bottom: 2px solid white;
- }
- &:last-child {
- &::after {
- width: calc(100% + 40px);
- }
- }
-`;
-
export const MenuTitle = styled.div`
font-size: 18px;
height: 100%;
line-height: 36px;
font-weight: ${({ isSelected }) => (isSelected ? '700' : '500')};
- color: ${({ type, isSelected }) =>
- type === 'sub' ? (isSelected ? '#fff' : 'rgba(255, 255, 255, 0.5)') : '#fff'};
+ color: ${colors.white};
cursor: pointer;
position: relative;
- ${({ isOpened }) => isOpened && menuTitleUnderline};
&:not(:last-child) {
padding-right: 40px;
}
&:hover {
- color: #fff;
- ${({ type }) => type !== 'sub' && menuTitleUnderline}
+ &::after {
+ content: '';
+ position: absolute;
+ top: 3.5rem; /* this is bad practice */
+ left: -20px;
+ width: 100%;
+ border-bottom: 2px solid ${colors.white};
+ }
+ &:last-child {
+ &::after {
+ width: calc(100% + 40px);
+ }
+ }
}
`;
-const ParentMenuTitle = styled(MenuTitle)`
- position: relative;
-`;
-
export default DesktopHeader;
diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx
index 3e2a3fe9..b6095b5a 100644
--- a/src/components/Header/Header.tsx
+++ b/src/components/Header/Header.tsx
@@ -1,18 +1,18 @@
import { useIsDesktop, useIsMobile, useIsTablet } from '@src/hooks/useDevice';
import DesktopHeader from './Desktop/DesktopHeader';
import MobileHeader from './Mobile/MobileHeader';
-import styles from './header.module.scss';
+import * as S from './style';
export function Header() {
- const isDesktop = useIsDesktop('992px');
- const isTablet = useIsTablet('766px', '991.9px');
+ const isDesktop = useIsDesktop('940px');
+ const isTablet = useIsTablet('768px', '939px');
const isMobile = useIsMobile();
return (
-
+
{isDesktop && }
{isTablet && }
{isMobile && }
-
+
);
}
diff --git a/src/components/Header/Mobile/HeaderMenu.style.ts b/src/components/Header/Mobile/HeaderMenu.style.ts
index 1a8798a9..4777fdcb 100644
--- a/src/components/Header/Mobile/HeaderMenu.style.ts
+++ b/src/components/Header/Mobile/HeaderMenu.style.ts
@@ -63,7 +63,7 @@ export const MenuWrap = styled.div`
export const Background = styled.div`
height: 100vh;
- background: #181818;
+ background: ${colors.gray950};
opacity: 0.8;
`;
@@ -110,7 +110,7 @@ export const ContentsWrap = styled.div`
display: flex;
flex-direction: column;
justify-content: space-between;
- background: #181818;
+ background: ${colors.gray950};
padding-top: 50px;
margin-bottom: 0px;
diff --git a/src/components/Header/Mobile/HeaderMenu.tsx b/src/components/Header/Mobile/HeaderMenu.tsx
index cff9138a..e5880e01 100644
--- a/src/components/Header/Mobile/HeaderMenu.tsx
+++ b/src/components/Header/Mobile/HeaderMenu.tsx
@@ -2,7 +2,7 @@ import Link from 'next/link';
import { useEffect } from 'react';
import useHeader from '@src/hooks/useHeader';
import { menuTapList } from '../menuTapList';
-import { BaseMenuTap, MenuState, MenuTapType } from '../types';
+import { MenuState, MenuTapType, SingleMenuTap } from '../types';
import * as S from './HeaderMenu.style';
function useNoScroll(isMenuShown: MenuState) {
@@ -27,7 +27,7 @@ interface HeaderMenuProps {
}
type MenuTapProps = {
- menuTap: BaseMenuTap;
+ menuTap: SingleMenuTap;
handleIsSelected: (path: string) => boolean;
};
@@ -47,18 +47,6 @@ function MenuTap({ menuTap, handleIsSelected }: MenuTapProps) {
{menuTap.title}
);
- case MenuTapType.Parent:
- return (
- <>
- {menuTap.children.map((childMenuTap) => (
-
- ))}
- >
- );
}
}
diff --git a/src/components/Header/header.module.scss b/src/components/Header/header.module.scss
deleted file mode 100644
index a4a41259..00000000
--- a/src/components/Header/header.module.scss
+++ /dev/null
@@ -1,26 +0,0 @@
-@import '@src/lib/styles/mixins';
-
-.wrapper {
- width: 100%;
- min-height: 80px;
- margin: 0 auto;
- display: flex;
- justify-content: center;
- align-items: center;
- position: fixed;
- background-color: rgba(22, 22, 28, 0.9);
- backdrop-filter: blur(20px);
- z-index: 100;
-
- @include tablet {
- height: 48px;
- padding: 0 48px;
- }
-
- @include mobile {
- height: 48px;
- min-height: 48px;
- padding: 0 20px;
- justify-content: space-between;
- }
-}
diff --git a/src/components/Header/menuTapList.ts b/src/components/Header/menuTapList.ts
index 98ee20dd..a8bb1663 100644
--- a/src/components/Header/menuTapList.ts
+++ b/src/components/Header/menuTapList.ts
@@ -12,20 +12,9 @@ export const menuTapList: MenuTapList = [
href: '/project',
},
{
- type: MenuTapType.Parent,
+ type: MenuTapType.Router,
title: '블로그',
- children: [
- {
- type: MenuTapType.Router,
- title: '활동후기',
- href: '/review',
- },
- {
- type: MenuTapType.Router,
- title: '솝티클',
- href: '/sopticle',
- },
- ],
+ href: '/blog',
},
{
type: MenuTapType.Router,
diff --git a/src/components/Header/style.ts b/src/components/Header/style.ts
new file mode 100644
index 00000000..08ceef24
--- /dev/null
+++ b/src/components/Header/style.ts
@@ -0,0 +1,30 @@
+import styled from '@emotion/styled';
+import { colors } from '@sopt-makers/colors';
+
+export const Wrapper = styled.header`
+ width: 100%;
+ min-height: 80px;
+ margin: 0 auto;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: fixed;
+ background-color: ${colors.gray950};
+ backdrop-filter: blur(20px);
+ z-index: 100;
+ padding: 0 20px;
+ top: 0;
+
+ /* 태블릿 + 데스크탑 뷰 */
+ @media (min-width: 768px) {
+ height: 48px;
+ }
+
+ /* 모바일 뷰 */
+ @media (max-width: 767px) {
+ height: 48px;
+ min-height: 48px;
+
+ justify-content: space-between;
+ }
+`;
diff --git a/src/components/Header/types.ts b/src/components/Header/types.ts
index 55a813b8..b1783b91 100644
--- a/src/components/Header/types.ts
+++ b/src/components/Header/types.ts
@@ -6,18 +6,10 @@ export const enum MenuTapType {
Parent = 'PARENT',
}
-export type ParentMenuTap = {
- type: MenuTapType.Parent;
- title: string;
- children: SingleMenuTap[];
-};
-
export type SingleMenuTap = {
type: MenuTapType.Router | MenuTapType.Anchor;
title: string;
href: string;
};
-export type BaseMenuTap = SingleMenuTap | ParentMenuTap;
-
-export type MenuTapList = BaseMenuTap[];
+export type MenuTapList = SingleMenuTap[];
diff --git a/src/lib/styles/colors.ts b/src/lib/styles/colors.ts
new file mode 100644
index 00000000..64ce3eba
--- /dev/null
+++ b/src/lib/styles/colors.ts
@@ -0,0 +1,79 @@
+export const colors = {
+ white: '#FFFFFF',
+ black: '#000000',
+
+ gray10: '#FCFCFC',
+ gray30: '#F0F0F0',
+ gray50: '#E4E4E5',
+ gray100: '#C3C3C6',
+ gray200: '#9D9DA4',
+ gray300: '#808087',
+ gray400: '#66666D',
+ gray500: '#515159',
+ gray600: '#3F3F47',
+ gray700: '#2E2E35',
+ gray800: '#202025',
+ gray950: '#0F0F12',
+
+ blue50: '#C8E1FF',
+ blue100: '#8FC0FF',
+ blue200: '#619EFF',
+ blue300: '#4485FF',
+ blue400: '#346FFA',
+ blue500: '#2C53DF',
+ blue600: '#2649B3',
+ blue700: '#253B8C',
+ blue800: '#23306A',
+ blue900: '#20274D',
+
+ red50: '#FFD1D3',
+ red100: '#FFA8AD',
+ red200: '#FE818B',
+ red300: '#FA616D',
+ red400: '#F04251',
+ red500: '#CA2F3D',
+ red600: '#9E2733',
+ red700: '#7A242D',
+ red800: '#562025',
+ red900: '#3C2020',
+
+ green50: '#CCFFEC',
+ green100: '#82F6CB',
+ green200: '#4EE4AD',
+ green300: '#26CF91',
+ green400: '#16BF81',
+ green500: '#13A06C',
+ green600: '#138A5E',
+ green700: '#136D4C',
+ green800: '#13533C',
+ green900: '#15372B',
+
+ yellow50: '#FFF4D4',
+ yellow100: '#FFE9B2',
+ yellow200: '#FFDE8A',
+ yellow300: '#FFCD59',
+ yellow400: '#FFC234',
+ yellow500: '#FFB326',
+ yellow600: '#EBA01E',
+ yellow700: '#B57B1D',
+ yellow800: '#72531E',
+ yellow900: '#3D301A',
+
+ orange50: '#FFECE5',
+ orange100: '#FFCEBD',
+ orange200: '#FFA480',
+ orange300: '#FF834A',
+ orange400: '#F77234',
+ orange500: '#D4591C',
+ orange600: '#AD4E17',
+ orange700: '#853D11',
+ orange800: '#5C2B0C',
+ orange900: '#422109',
+
+ attention: '#FFC234',
+ error: '#F04251',
+ background: '#0F0F12',
+ secondary: '#F77234',
+ success: '#346FFA',
+ information: '#16BF81',
+};
diff --git a/src/lib/styles/global.ts b/src/lib/styles/global.ts
index f38426db..3a89d308 100644
--- a/src/lib/styles/global.ts
+++ b/src/lib/styles/global.ts
@@ -80,7 +80,7 @@ export const global = css`
}
body {
- background-color: #16161c;
+ background-color: #0f0f12;
line-height: 1;
}
diff --git a/src/pages/blog.tsx b/src/pages/blog.tsx
new file mode 100644
index 00000000..29da1c6a
--- /dev/null
+++ b/src/pages/blog.tsx
@@ -0,0 +1 @@
+export { default } from '@src/views/BlogPage';
diff --git a/src/views/BlogPage/BlogPage.tsx b/src/views/BlogPage/BlogPage.tsx
new file mode 100644
index 00000000..285c20bf
--- /dev/null
+++ b/src/views/BlogPage/BlogPage.tsx
@@ -0,0 +1,10 @@
+import PageLayout from '@src/components/common/PageLayout';
+import BlogTab from './components/blogTab';
+
+export default function BlogPage() {
+ return (
+
+
+
+ );
+}
diff --git a/src/views/BlogPage/components/blogTab/index.tsx b/src/views/BlogPage/components/blogTab/index.tsx
new file mode 100644
index 00000000..c8cd633d
--- /dev/null
+++ b/src/views/BlogPage/components/blogTab/index.tsx
@@ -0,0 +1,39 @@
+import { useState } from 'react';
+import * as S from './style';
+import { BlogTabList } from './types';
+
+export default function BlogTab() {
+ const [selectedTab, setSelectedTab] = useState('REVIEW');
+ const blogTabList: BlogTabList = {
+ REVIEW: {
+ title: '활동후기',
+ description: '회원들의 진솔한 후기를 통해 SOPT를 미리 만나보세요. ',
+ },
+ ARTICLE: {
+ title: '아티클',
+ description: '회원들의 아티클을 통해 SOPT에서 얻은 인사이트를 확인해보세요.',
+ },
+ };
+
+ return (
+
+
+
+ {Object.entries(blogTabList).map(([blogTab, tabInfo]) => {
+ return (
+ setSelectedTab(blogTab as keyof BlogTabList)}
+ isSelected={selectedTab === blogTab}
+ >
+ {tabInfo.title}
+
+ );
+ })}
+
+ {blogTabList[selectedTab]?.description}
+ 드롭다운 들어가는 부분
+
+
+ );
+}
diff --git a/src/views/BlogPage/components/blogTab/style.ts b/src/views/BlogPage/components/blogTab/style.ts
new file mode 100644
index 00000000..4ba9d40b
--- /dev/null
+++ b/src/views/BlogPage/components/blogTab/style.ts
@@ -0,0 +1,102 @@
+import styled from '@emotion/styled';
+import { colors } from '@sopt-makers/colors';
+
+export const Wrapper = styled.section`
+ width: 100%;
+ margin-top: 188px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ /* 태블릿 뷰 */
+ @media (max-width: 939px) and (min-width: 768px) {
+ margin-top: 188px;
+ }
+ /* 모바일 뷰 */
+ @media (max-width: 767px) {
+ margin-top: 76px;
+ }
+`;
+
+export const Container = styled.main`
+ width: 900px;
+ display: flex;
+ align-items: flex-start;
+ flex-direction: column;
+
+ /* 태블릿, 모바일 뷰 */
+ @media (max-width: 939px) {
+ margin-left: 20px;
+ margin-right: 20px;
+ width: 100%;
+ }
+`;
+
+export const TabContainer = styled.section`
+ display: flex;
+ align-items: center;
+`;
+
+interface MenuTitleProps {
+ isSelected: boolean;
+}
+
+export const TabTitle = styled.article`
+ font-size: 24px;
+ height: 100%;
+ line-height: 36px;
+ font-weight: 700;
+ letter-spacing: -0.48px;
+
+ color: ${({ isSelected }) => (isSelected ? `${colors.gray30}` : `${colors.gray300}`)};
+
+ cursor: pointer;
+ position: relative;
+ border-bottom: ${({ isSelected }) => isSelected && `2px solid ${colors.gray200}`};
+
+ padding-bottom: 16px;
+ margin-right: 20px;
+
+ /* 모바일 뷰 */
+ @media (max-width: 767px) {
+ border-bottom: ${({ isSelected }) => isSelected && `1px solid ${colors.gray200}`};
+ margin-right: 12px;
+ }
+
+ &:hover {
+ color: ${colors.gray100};
+ }
+`;
+
+export const TabDescription = styled.h1`
+ margin-top: 24px;
+ margin-bottom: 48px;
+ word-break: keep-all;
+
+ font-size: 20px;
+ font-weight: 600;
+ line-height: 30px;
+ letter-spacing: -0.4px;
+ color: ${colors.gray100};
+ width: 100%;
+
+ /* 모바일 뷰 */
+ @media (max-width: 767px) {
+ margin-top: 14px;
+ margin-bottom: 16px;
+ display: flex;
+
+ padding: 16px;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 10px;
+ border-radius: 12px;
+ background: ${colors.gray800};
+
+ font-size: 14px;
+ font-weight: 500;
+ line-height: 23.1px;
+ letter-spacing: -0.21px;
+ color: ${colors.gray30};
+ }
+`;
diff --git a/src/views/BlogPage/components/blogTab/types.ts b/src/views/BlogPage/components/blogTab/types.ts
new file mode 100644
index 00000000..b14bb9ac
--- /dev/null
+++ b/src/views/BlogPage/components/blogTab/types.ts
@@ -0,0 +1,10 @@
+export interface BlogTabList {
+ REVIEW: {
+ title: string;
+ description: string;
+ };
+ ARTICLE: {
+ title: string;
+ description: string;
+ };
+}
diff --git a/src/views/BlogPage/index.tsx b/src/views/BlogPage/index.tsx
new file mode 100644
index 00000000..75531ca0
--- /dev/null
+++ b/src/views/BlogPage/index.tsx
@@ -0,0 +1 @@
+export { default } from './BlogPage';