Skip to content

Commit

Permalink
Merge pull request #228 from sopt-makers/feat/#218-blog-tab-navigation
Browse files Browse the repository at this point in the history
[SP2] blog tab navigation
  • Loading branch information
f0rever0 authored Oct 23, 2023
2 parents ef8bb91 + 173801f commit d4c4beb
Show file tree
Hide file tree
Showing 17 changed files with 309 additions and 224 deletions.
2 changes: 1 addition & 1 deletion src/components/Footer/OriginFooter/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
176 changes: 23 additions & 153 deletions src/components/Header/Desktop/DesktopHeader.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
Expand All @@ -20,147 +19,44 @@ function DesktopHeader() {
</CenterAligner>
<MenuTitlesWrapper>
{menuTapList.map((menuTap) => (
<MenuTap
key={menuTap.title}
menuTap={menuTap}
handleIsSelected={handleIsSelected}
isSubTapOpened={isSubTapOpened}
setIsSubTapOpened={setIsSubTapOpened}
/>
<MenuTap key={menuTap.title} menuTap={menuTap} handleIsSelected={handleIsSelected} />
))}
</MenuTitlesWrapper>
</Wrapper>
{isSubTapOpened && <SubMenuWrapper />}
</>
);
}

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 (
<MenuTitleAnchor
href={menuTap.href}
target="_blank"
rel="noreferrer"
onClick={() => setIsSubTapOpened(false)}
onMouseEnter={() => setIsSubTapOpened(false)}
>
<MenuTitleAnchor href={menuTap.href} target="_blank" rel="noreferrer">
{menuTap.title}
</MenuTitleAnchor>
);
case MenuTapType.Router:
return (
<MenuTitle
isSelected={handleIsSelected(menuTap.href)}
onClick={() => setIsSubTapOpened(false)}
onMouseEnter={() => setIsSubTapOpened(false)}
>
<MenuTitle isSelected={handleIsSelected(menuTap.href)}>
<Link href={menuTap.href}>{menuTap.title}</Link>
</MenuTitle>
);
case MenuTapType.Parent:
return (
<ParentMenu
menuTap={menuTap}
handleIsSelected={handleIsSelected}
isSubTapOpened={isSubTapOpened}
setIsSubTapOpened={setIsSubTapOpened}
/>
);
}
}

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 (
<ParentMenuTitle
isSelected={handleIsSelected(menuTap.children.map((t) => t.href))}
isOpened={isOpened}
onMouseEnter={onMouseIn}
onClick={(e) => e.stopPropagation()}
>
{menuTap.title}
{isOpened && (
<SubMenu>
{menuTap.children.map((c) => {
switch (c.type) {
case MenuTapType.Anchor:
return (
<MenuTitle type="sub" key={c.title}>
<MenuTitleAnchor href={c.href} target="_blank" rel="noreferrer">
{c.title}
</MenuTitleAnchor>
</MenuTitle>
);
case MenuTapType.Router:
return (
<MenuTitle type="sub" isSelected={handleIsSelected(c.href)} key={c.title}>
<Link href={c.href}>{c.title}</Link>
</MenuTitle>
);
}
})}
</SubMenu>
)}
</ParentMenuTitle>
);
}

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;
`;
Expand All @@ -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;
Expand Down Expand Up @@ -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<MenuTitleProps>`
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;
10 changes: 5 additions & 5 deletions src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<header className={styles.wrapper}>
<S.Wrapper>
{isDesktop && <DesktopHeader />}
{isTablet && <MobileHeader />}
{isMobile && <MobileHeader />}
</header>
</S.Wrapper>
);
}
4 changes: 2 additions & 2 deletions src/components/Header/Mobile/HeaderMenu.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const MenuWrap = styled.div`

export const Background = styled.div`
height: 100vh;
background: #181818;
background: ${colors.gray950};
opacity: 0.8;
`;

Expand Down Expand Up @@ -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;
Expand Down
16 changes: 2 additions & 14 deletions src/components/Header/Mobile/HeaderMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -27,7 +27,7 @@ interface HeaderMenuProps {
}

type MenuTapProps = {
menuTap: BaseMenuTap;
menuTap: SingleMenuTap;
handleIsSelected: (path: string) => boolean;
};

Expand All @@ -47,18 +47,6 @@ function MenuTap({ menuTap, handleIsSelected }: MenuTapProps) {
<Link href={menuTap.href}>{menuTap.title}</Link>
</S.MenuTitle>
);
case MenuTapType.Parent:
return (
<>
{menuTap.children.map((childMenuTap) => (
<MenuTap
key={childMenuTap.title}
menuTap={childMenuTap}
handleIsSelected={handleIsSelected}
/>
))}
</>
);
}
}

Expand Down
26 changes: 0 additions & 26 deletions src/components/Header/header.module.scss

This file was deleted.

15 changes: 2 additions & 13 deletions src/components/Header/menuTapList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading

0 comments on commit d4c4beb

Please sign in to comment.