From b03ace95d3e2ef120c30d67a3c422a2f3914f56e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=8F=84=ED=98=84?= <77152650+Creative-Lee@users.noreply.github.com> Date: Wed, 4 Oct 2023 10:52:50 +0900 Subject: [PATCH] =?UTF-8?q?Refactor/#465=20=EB=8D=B0=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=ED=83=91=20=ED=99=98=EA=B2=BD=EC=97=90=EC=84=9C=20=EC=8A=A4?= =?UTF-8?q?=EC=99=80=EC=9D=B4=ED=94=84=EA=B0=80=20=EB=8F=99=EC=9E=91?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=A0=88=EC=9D=B4=EC=95=84?= =?UTF-8?q?=EC=9B=83=EC=9D=84=20=EA=B0=9C=EC=84=A0=ED=95=9C=EB=8B=A4.=20?= =?UTF-8?q?=20(#487)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Flex 레이아웃 컴포넌트 구현 * design: PC 반응형 디자인 개선 임시 저장 * refactor: Flex 컴포넌트 개선 프로젝트 반응형 사이즈 대응 prop 추가 및 type 선언 * feat: breakPoint type 추가 * design: youtube 컴포넌트의 flex wrapping 제거 * fix: 스타일 컴포넌트가 잘못 참조했던 Flex 컴포넌트 수정 ref 정상 동작하도록 변경 * design: 1페이지 단위의 높이를 가지도록 디자인 변경 * design: 인터페이스 상단 수평선 맞춤 * design: 모든 디바이스에서 스크롤 스냅 적용 * design: 전체 컨테이너의 배경색을 넣어 공간감을 줌 * design: Layout의 상하단 패딩 제거 및 스와이프 관련 컴포넌트 높이 고정 1. 기존 Header를 sticky -> fixed 로 변경하면서, 스와이프 아이템에 header 만큼의 padding-top을 부여하였음. 2. 때문에 더이상 필요하지 않은 반응형 높이 제어를 속성들을 삭제하고 100vh로 고정 3. 마찬가지로 혼동을 주는 Layout의 상하단 padding 삭제 및 0으로 고정 * design: 스크롤 이슈로 main 영역 padding 줄임 * design: 가수, 제목 텍스트 디테일 처리로 듣기 인터페이스 짤리지 않도록 함 * design: FHD 기준 좌우 padding 수정 * refactor: as prop $ 제거 및 default parameter 적용 * refactor(Flex): react 컴포넌트-> styled 컴포넌트로 변경 이미 스타일 컴포넌트가 제공하고 있는 다형성, html attribytes 관련 type 중복을 제거함. * style: 스타일 린트 적용 --- .../songs/components/KillingPartInterface.tsx | 10 ++- .../songs/components/SongDetailItem.tsx | 55 +++++++++------ frontend/src/pages/EditProfilePage.tsx | 2 +- frontend/src/pages/LoginPage.tsx | 3 +- frontend/src/pages/SongDetailListPage.tsx | 32 ++------- frontend/src/shared/components/Flex/Flex.tsx | 69 +++++++++++++++++++ .../src/shared/components/Layout/Header.tsx | 5 +- .../src/shared/components/Layout/Layout.tsx | 14 ++-- frontend/src/shared/styles/GlobalStyles.ts | 2 +- frontend/src/shared/styles/theme.ts | 7 -- frontend/src/shared/types/theme.ts | 4 +- 11 files changed, 131 insertions(+), 72 deletions(-) create mode 100644 frontend/src/shared/components/Flex/Flex.tsx diff --git a/frontend/src/features/songs/components/KillingPartInterface.tsx b/frontend/src/features/songs/components/KillingPartInterface.tsx index ec89b4ebe..b2aec0997 100644 --- a/frontend/src/features/songs/components/KillingPartInterface.tsx +++ b/frontend/src/features/songs/components/KillingPartInterface.tsx @@ -2,6 +2,7 @@ import { useEffect, useRef, useState } from 'react'; import { styled } from 'styled-components'; import CommentList from '@/features/comments/components/CommentList'; import useVideoPlayerContext from '@/features/youtube/hooks/useVideoPlayerContext'; +import Flex from '@/shared/components/Flex/Flex'; import Spacing from '@/shared/components/Spacing'; import useTimerContext from '@/shared/components/Timer/hooks/useTimerContext'; import ToggleSwitch from '@/shared/components/ToggleSwitch/ToggleSwitch'; @@ -120,7 +121,7 @@ const KillingPartInterface = ({ killingParts, songId }: KillingPartInterfaceProp }, [pause]); return ( - <> + @@ -147,7 +148,7 @@ const KillingPartInterface = ({ killingParts, songId }: KillingPartInterfaceProp {commentsPartId !== DEFAULT_PART_ID && ( )} - + ); }; @@ -186,4 +187,9 @@ const FlexContainer = styled.div` display: flex; align-items: center; justify-content: space-between; + height: 60px; + + @media (max-width: ${({ theme }) => theme.breakPoints.md}) { + height: auto; + } `; diff --git a/frontend/src/features/songs/components/SongDetailItem.tsx b/frontend/src/features/songs/components/SongDetailItem.tsx index cfb76f912..b69d40b14 100644 --- a/frontend/src/features/songs/components/SongDetailItem.tsx +++ b/frontend/src/features/songs/components/SongDetailItem.tsx @@ -5,7 +5,7 @@ import KillingPartInterface from '@/features/songs/components/KillingPartInterfa import Thumbnail from '@/features/songs/components/Thumbnail'; import { VideoPlayerProvider } from '@/features/youtube/components/VideoPlayerProvider'; import Youtube from '@/features/youtube/components/Youtube'; -import Flex from '@/shared/components/Flex'; +import Flex from '@/shared/components/Flex/Flex'; import Spacing from '@/shared/components/Spacing'; import SRHeading from '@/shared/components/SRHeading'; import TimerProvider from '@/shared/components/Timer/TimerProvider'; @@ -43,20 +43,27 @@ const SongDetailItem = forwardRef( return ( 킬링파트 듣기 페이지 - - - - {title} - {singer} - - - - - - - - + + + + + + {title} + {singer} + + + + + + + + +
@@ -68,9 +75,10 @@ SongDetailItem.displayName = 'SongDetailItem'; export default SongDetailItem; -const Container = styled(Flex)` +const Container = styled.div` + display: flex; flex-direction: column; - height: 100%; + height: 100vh; padding-top: ${({ theme: { headerHeight } }) => headerHeight.desktop}; @media (max-width: ${({ theme }) => theme.breakPoints.xs}) { @@ -97,15 +105,22 @@ const SongInfoContainer = styled.div` const Info = styled.div``; const SongTitle = styled.div` - height: 30px; font-size: 20px; font-weight: 700; color: ${({ theme: { color } }) => color.white}; - @media (max-width: ${({ theme }) => theme.breakPoints.md}) { + @media (max-width: ${({ theme }) => theme.breakPoints.lg}) { + width: 220px; font-size: 18px; } + @media (max-width: ${({ theme }) => theme.breakPoints.xs}) { + overflow: hidden; + font-size: 16px; + text-overflow: ellipsis; + white-space: nowrap; + } + @media (max-width: ${({ theme }) => theme.breakPoints.xxs}) { font-size: 16px; } @@ -116,11 +131,11 @@ const Singer = styled.div` font-weight: 700; color: ${({ theme: { color } }) => color.subText}; - @media (max-width: ${({ theme }) => theme.breakPoints.md}) { + @media (max-width: ${({ theme }) => theme.breakPoints.lg}) { font-size: 16px; } - @media (max-width: ${({ theme }) => theme.breakPoints.xxs}) { + @media (max-width: ${({ theme }) => theme.breakPoints.xs}) { font-size: 14px; } `; diff --git a/frontend/src/pages/EditProfilePage.tsx b/frontend/src/pages/EditProfilePage.tsx index 1ca633601..4191e8e0c 100644 --- a/frontend/src/pages/EditProfilePage.tsx +++ b/frontend/src/pages/EditProfilePage.tsx @@ -95,8 +95,8 @@ const disabledStyle = css<{ disabled: boolean }>` const Input = styled.input<{ disabled: boolean }>` ${disabledStyle}; - font-size: 16px; padding: 0 8px; + font-size: 16px; `; const TextArea = styled.textarea<{ disabled: boolean }>` diff --git a/frontend/src/pages/LoginPage.tsx b/frontend/src/pages/LoginPage.tsx index 68e9aefe8..2b18b499a 100644 --- a/frontend/src/pages/LoginPage.tsx +++ b/frontend/src/pages/LoginPage.tsx @@ -109,11 +109,12 @@ const PlatformName = styled.div` display: flex; align-items: center; justify-content: center; - text-align: center; width: 400px; height: 60px; + text-align: center; + border-radius: 12px; @media (max-width: ${({ theme }) => theme.breakPoints.xs}) { diff --git a/frontend/src/pages/SongDetailListPage.tsx b/frontend/src/pages/SongDetailListPage.tsx index 353b6055e..7c14447b3 100644 --- a/frontend/src/pages/SongDetailListPage.tsx +++ b/frontend/src/pages/SongDetailListPage.tsx @@ -144,34 +144,14 @@ export const ObservingTrigger = styled.div` `; export const ItemContainer = styled.div` + scroll-snap-type: y mandatory; + overflow-y: scroll; width: 100%; + height: 100vh; - @media (max-width: ${({ theme }) => theme.breakPoints.md}) { - scroll-snap-type: y mandatory; - overflow-y: scroll; - height: calc( - ${({ theme: { mainTopBottomPadding } }) => { - return `100vh - ${mainTopBottomPadding.tablet} * 2`; - }} - ); - - & > div[role='article'] { - scroll-snap-align: start; - scroll-snap-stop: always; - } - } - - @media (max-width: ${({ theme }) => theme.breakPoints.xxs}) { - height: calc( - ${({ theme: { mainTopBottomPadding } }) => { - return `100vh - ${mainTopBottomPadding.xxs} * 2`; - }} - ); - - & > div[role='article'] { - scroll-snap-align: start; - scroll-snap-stop: always; - } + & > div[role='article'] { + scroll-snap-align: start; + scroll-snap-stop: always; } `; diff --git a/frontend/src/shared/components/Flex/Flex.tsx b/frontend/src/shared/components/Flex/Flex.tsx new file mode 100644 index 000000000..83818cf7c --- /dev/null +++ b/frontend/src/shared/components/Flex/Flex.tsx @@ -0,0 +1,69 @@ +import styled, { css } from 'styled-components'; +import type { BreakPoints } from '@/shared/types/theme'; +import type { CSSProp } from 'styled-components'; + +interface FlexBox { + $direction?: React.CSSProperties['flexDirection']; + $wrap?: React.CSSProperties['flexWrap']; + $gap?: number; + $align?: React.CSSProperties['alignItems']; + $justify?: React.CSSProperties['justifyContent']; + $css?: CSSProp; +} + +interface ResponsiveFlexBox extends Partial> {} + +interface FlexProps extends FlexBox, ResponsiveFlexBox {} + +const Flex = styled.div` + display: flex; + flex-direction: ${({ $direction = 'row' }) => $direction}; + flex-wrap: ${({ $wrap = 'nowrap' }) => $wrap}; + gap: ${({ $gap = 0 }) => `${$gap}px`}; + align-items: ${({ $align = 'stretch' }) => $align}; + justify-content: ${({ $justify = 'flex-start' }) => $justify}; + ${({ $css }) => $css} + + @media (max-width: ${({ theme }) => theme.breakPoints.xxl}) { + ${({ $xxl }) => flexCss($xxl)} + } + + @media (max-width: ${({ theme }) => theme.breakPoints.xl}) { + ${({ $xl }) => flexCss($xl)} + } + + @media (max-width: ${({ theme }) => theme.breakPoints.lg}) { + ${({ $lg }) => flexCss($lg)} + } + + @media (max-width: ${({ theme }) => theme.breakPoints.md}) { + ${({ $md }) => flexCss($md)} + } + + @media (max-width: ${({ theme }) => theme.breakPoints.sm}) { + ${({ $sm }) => flexCss($sm)} + } + + @media (max-width: ${({ theme }) => theme.breakPoints.xs}) { + ${({ $xs }) => flexCss($xs)} + } + + @media (max-width: ${({ theme }) => theme.breakPoints.xxs}) { + ${({ $xxs }) => flexCss($xxs)} + } +`; + +export default Flex; + +const flexCss = (flexBox?: FlexBox) => { + if (!flexBox) return; + const { $align, $direction, $gap, $justify, $wrap } = flexBox; + + return css` + flex-direction: ${$direction}; + flex-wrap: ${$wrap}; + gap: ${$gap && `${$gap}px`}; + align-items: ${$align}; + justify-content: ${$justify}; + `; +}; diff --git a/frontend/src/shared/components/Layout/Header.tsx b/frontend/src/shared/components/Layout/Header.tsx index aaf3c48bd..e3201c7f6 100644 --- a/frontend/src/shared/components/Layout/Header.tsx +++ b/frontend/src/shared/components/Layout/Header.tsx @@ -40,11 +40,11 @@ const Container = styled.header` width: 100%; height: ${({ theme }) => theme.headerHeight.desktop}; - padding: 0 16.66%; + padding: 0 12.33%; background-color: ${({ theme: { color } }) => color.black}; - @media (max-width: ${({ theme }) => theme.breakPoints.xl}) { + @media (max-width: ${({ theme }) => theme.breakPoints.xxl}) { padding: 0 8.33%; } @@ -59,7 +59,6 @@ const Container = styled.header` @media (max-width: ${({ theme }) => theme.breakPoints.xxs}) { height: ${({ theme }) => theme.headerHeight.xxs}; - padding: 0 16px; } `; diff --git a/frontend/src/shared/components/Layout/Layout.tsx b/frontend/src/shared/components/Layout/Layout.tsx index e34f96cda..a0d6aaf7a 100644 --- a/frontend/src/shared/components/Layout/Layout.tsx +++ b/frontend/src/shared/components/Layout/Layout.tsx @@ -22,25 +22,21 @@ const LayoutContainer = styled.main` width: 100%; min-height: 100vh; - padding: ${({ theme: { mainTopBottomPadding } }) => `${mainTopBottomPadding.desktop} 16.66%`}; + padding: 0 12.33%; color: ${({ theme: { color } }) => color.white}; background-color: ${({ theme: { color } }) => color.black}; - @media (max-width: ${({ theme }) => theme.breakPoints.xl}) { - padding: ${({ theme: { mainTopBottomPadding } }) => `${mainTopBottomPadding.desktop} 8.33%`}; + @media (max-width: ${({ theme }) => theme.breakPoints.xxl}) { + padding: 0 8.33%; } @media (max-width: ${({ theme }) => theme.breakPoints.md}) { - padding: ${({ theme: { mainTopBottomPadding } }) => `${mainTopBottomPadding.tablet} 4.16%`}; - } - - @media (max-width: ${({ theme }) => theme.breakPoints.xs}) { - padding: ${({ theme: { mainTopBottomPadding } }) => `${mainTopBottomPadding.tablet} 4.16%`}; + padding: 0 4.16%; } @media (max-width: ${({ theme }) => theme.breakPoints.xxs}) { - padding: ${({ theme: { mainTopBottomPadding } }) => `${mainTopBottomPadding.xxs} 16px`}; + padding: 0 16px; } `; diff --git a/frontend/src/shared/styles/GlobalStyles.ts b/frontend/src/shared/styles/GlobalStyles.ts index b1f6e3913..e34e3eed7 100644 --- a/frontend/src/shared/styles/GlobalStyles.ts +++ b/frontend/src/shared/styles/GlobalStyles.ts @@ -18,9 +18,9 @@ const GlobalStyles = createGlobalStyle` color: inherit; &::-webkit-scrollbar { display: none; - background: transparent; width: 0; height: 0; + background: transparent; } } *, diff --git a/frontend/src/shared/styles/theme.ts b/frontend/src/shared/styles/theme.ts index 0824ae00b..06172117b 100644 --- a/frontend/src/shared/styles/theme.ts +++ b/frontend/src/shared/styles/theme.ts @@ -37,13 +37,6 @@ const theme = { tablet: '80px', desktop: '80px', }, - - mainTopBottomPadding: { - xxs: '8px', - mobile: '16px', - tablet: '16px', - desktop: '36px', - }, } as const; export default theme; diff --git a/frontend/src/shared/types/theme.ts b/frontend/src/shared/types/theme.ts index d761ce1f2..bd038daa8 100644 --- a/frontend/src/shared/types/theme.ts +++ b/frontend/src/shared/types/theme.ts @@ -1,4 +1,4 @@ -// eslint-disable-next-line -import theme from '@/shared/styles/theme'; +import type theme from '@/shared/styles/theme'; export type ThemeType = typeof theme; +export type BreakPoints = keyof typeof theme.breakPoints;