From 22f5ccc152d6ab668009a9543f3812e1a0e9ac93 Mon Sep 17 00:00:00 2001 From: steven-yn Date: Wed, 21 Feb 2024 02:44:33 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20normal=20project=20=EB=B0=98=EC=9D=91?= =?UTF-8?q?=ED=98=95=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Card/Project/ProjectCard.context.ts | 3 +- .../Card/Project/ProjectCard.css.ts | 119 ++++++++++++++++-- .../Card/Project/ProjectCard.test.tsx | 2 - src/components/Card/Project/ProjectCard.tsx | 67 +++++++--- src/components/MainProject/MainProject.css.ts | 15 ++- .../NormalProject/NormalProject.context.ts | 2 + .../NormalProject/NormalProject.css.ts | 40 ++++-- .../NormalProject/NormalProject.tsx | 93 +++++++++----- .../getButtonPositionWithBreakPoints.ts | 2 +- .../getCardWidthWithBreakPoints.ts | 14 +++ .../getSlidesToShowWithBreakPoints.ts | 16 +++ src/components/Project/Project.css.ts | 5 + src/composable/Container/Container.css.ts | 3 +- src/hook/useResizeObserver.ts | 28 +++++ .../Components/Card/ProjectCard.stories.tsx | 8 -- src/types/designToken/BreakPoints.d.ts | 1 - 16 files changed, 329 insertions(+), 89 deletions(-) create mode 100644 src/components/NormalProject/getCardWidthWithBreakPoints.ts create mode 100644 src/components/NormalProject/getSlidesToShowWithBreakPoints.ts create mode 100644 src/hook/useResizeObserver.ts diff --git a/src/components/Card/Project/ProjectCard.context.ts b/src/components/Card/Project/ProjectCard.context.ts index 3e64d74..8d97970 100644 --- a/src/components/Card/Project/ProjectCard.context.ts +++ b/src/components/Card/Project/ProjectCard.context.ts @@ -1,7 +1,7 @@ import { createStaticContext } from '@/utils/context/StaticContext'; export interface ProjectCardContextProps { - sizeToken: SizeToken; + sizeToken?: SizeToken; name: string; content?: string; period: string; @@ -10,7 +10,6 @@ export interface ProjectCardContextProps { } const StaticContextProjectCard = createStaticContext({ - sizeToken: 'LARGE', name: '', content: '', period: '', diff --git a/src/components/Card/Project/ProjectCard.css.ts b/src/components/Card/Project/ProjectCard.css.ts index 4a9b71c..e254ecc 100644 --- a/src/components/Card/Project/ProjectCard.css.ts +++ b/src/components/Card/Project/ProjectCard.css.ts @@ -1,15 +1,46 @@ import { style, styleVariants } from '@vanilla-extract/css'; +import { ODSBreakpointTokenVariables } from '@/const/breakpoints'; +import { ODSTextTokenVariables } from '@/const/fonts'; import { fontVariants } from '@/styles/common/font.css'; import { textPreStyle } from '@/styles/common/text.css'; -const wrapStyle = style({ +export const wrapStyle = style({ borderRadius: '0.75rem', + + paddingTop: '1.5rem', + + '@media': { + [ODSBreakpointTokenVariables['breakpoint-l']]: { + paddingTop: '1.32rem', + }, + + [ODSBreakpointTokenVariables['breakpoint-m']]: { + paddingTop: '1.25rem', + }, + }, }); export const wrapVariants = styleVariants({ - LARGE: [wrapStyle, { paddingTop: '1.5rem' }], - MEDIUM: [wrapStyle, { paddingTop: '1.32rem' }], - SMALL: [wrapStyle, { paddingTop: '1.25rem' }], + LARGE: { paddingTop: '1.5rem' }, + MEDIUM: { paddingTop: '1.32rem' }, + SMALL: { paddingTop: '1.25rem' }, +}); + +export const sizeStyle = style({ + width: '25.5rem', + height: '25.5rem', + + '@media': { + [ODSBreakpointTokenVariables['breakpoint-l']]: { + width: '22.5rem', + height: '22.5rem', + }, + + [ODSBreakpointTokenVariables['breakpoint-m']]: { + width: '17.5rem', + height: '22.5rem', + }, + }, }); export const sizeVariants = styleVariants({ @@ -27,6 +58,20 @@ export const sizeVariants = styleVariants({ }, }); +export const gapStyle = style({ + gap: '1rem', + + '@media': { + [ODSBreakpointTokenVariables['breakpoint-l']]: { + gap: '0.88238rem', + }, + + [ODSBreakpointTokenVariables['breakpoint-m']]: { + gap: '1rem', + }, + }, +}); + export const gapVariants = styleVariants({ LARGE: { gap: '1rem', @@ -39,42 +84,92 @@ export const gapVariants = styleVariants({ }, }); -const nameStyle = style([textPreStyle]); +export const nameStyle = style([ + textPreStyle, + { + padding: '0 1.5rem', + ...ODSTextTokenVariables['title-m-bold'], + + '@media': { + [ODSBreakpointTokenVariables['breakpoint-l']]: { + padding: '0 1.32rem', + ...ODSTextTokenVariables['title-s-semibold'], + }, -const descriptionStyle = style([textPreStyle]); + [ODSBreakpointTokenVariables['breakpoint-m']]: { + padding: '0 1.25rem', + ...ODSTextTokenVariables['paragraph-l-bold'], + }, + }, + }, +]); export const nameVariants = styleVariants({ - LARGE: [nameStyle, fontVariants['title-m-bold'], { padding: '0 1.5rem' }], + LARGE: [textPreStyle, fontVariants['title-m-bold'], { padding: '0 1.5rem' }], MEDIUM: [ - nameStyle, + textPreStyle, fontVariants['title-s-semibold'], { padding: '0 1.32rem' }, ], SMALL: [ - nameStyle, + textPreStyle, fontVariants['paragraph-l-bold'], { padding: '0 1.25rem' }, ], }); +export const descriptionStyle = style([ + textPreStyle, + { + padding: '0 1.5rem', + ...ODSTextTokenVariables['paragraph-s-regular'], + + '@media': { + [ODSBreakpointTokenVariables['breakpoint-l']]: { + padding: '0 1.32rem', + ...ODSTextTokenVariables['paragraph-s-regular'], + }, + + [ODSBreakpointTokenVariables['breakpoint-m']]: { + padding: '0 1.25rem', + ...ODSTextTokenVariables['paragraph-m-medium'], + }, + }, + }, +]); + export const descriptionVariants = styleVariants({ LARGE: [ - descriptionStyle, + textPreStyle, fontVariants['paragraph-s-regular'], { padding: '0 1.5rem' }, ], MEDIUM: [ - descriptionStyle, + textPreStyle, fontVariants['paragraph-s-regular'], { padding: '0 1.32rem' }, ], SMALL: [ - descriptionStyle, + textPreStyle, fontVariants['paragraph-m-medium'], { padding: '0 1.25rem' }, ], }); +export const periodStyle = style({ + marginLeft: '1.5rem', + + '@media': { + [ODSBreakpointTokenVariables['breakpoint-l']]: { + marginLeft: '1.32rem', + }, + + [ODSBreakpointTokenVariables['breakpoint-m']]: { + marginLeft: '1.25rem', + }, + }, +}); + export const periodVariants = styleVariants({ LARGE: { marginLeft: '1.5rem' }, MEDIUM: { marginLeft: '1.32rem' }, diff --git a/src/components/Card/Project/ProjectCard.test.tsx b/src/components/Card/Project/ProjectCard.test.tsx index 487bf96..5f76d06 100644 --- a/src/components/Card/Project/ProjectCard.test.tsx +++ b/src/components/Card/Project/ProjectCard.test.tsx @@ -5,8 +5,6 @@ describe('ProjectCard 컴포넌트', () => { const mockProps: ProjectCardProps = { visible_status: 'VISIBLE', sizeToken: 'LARGE', - projectMode: 'MAIN', - projectStatus: 'CURRENT', name: '프로젝트 이름', content: '프로젝트 설명', period: '2021-2022', diff --git a/src/components/Card/Project/ProjectCard.tsx b/src/components/Card/Project/ProjectCard.tsx index 6d1d54e..c2c9de5 100644 --- a/src/components/Card/Project/ProjectCard.tsx +++ b/src/components/Card/Project/ProjectCard.tsx @@ -3,6 +3,7 @@ import React, { PropsWithChildren } from 'react'; import Chip from '@/composable/Chip/Chip'; import Grid from '@/composable/Grid/Grid'; import ODSNextImage from '@/composable/Image/ODSNextImage'; +import { ODSImageTokenVariables } from '@/const/images'; import { backgroundColorVariants, colorVariants, @@ -12,28 +13,30 @@ import StaticContextProjectCard, { ProjectCardContextProps, } from './ProjectCard.context'; import { + descriptionStyle, descriptionVariants, + gapStyle, gapVariants, imageStyle, + nameStyle, nameVariants, + periodStyle, periodVariants, + sizeStyle, sizeVariants, + wrapStyle, wrapVariants, } from './ProjectCard.css'; export interface ProjectCardProps extends ProjectCardContextProps { className?: string; visible_status: VisibleStatusToken; - projectMode: ProjectModeToken; - projectStatus: EndTimeToken; } const ProjectCard = ({ - className, children, + className, visible_status, - // projectMode, - // projectStatus, sizeToken, name, content, @@ -57,10 +60,13 @@ const ProjectCard = ({ @@ -76,7 +82,8 @@ const Name = () => { return (

@@ -91,7 +98,8 @@ const Description = () => { return (

@@ -104,7 +112,10 @@ const Period = () => { const { sizeToken, period } = getStaticContext(StaticContextProjectCard); return ( {period} @@ -112,10 +123,14 @@ const Period = () => { ); }; -const Image = () => { +interface ImageProps { + breakPointsToken?: BreakPointsToken; +} + +const Image = ({ breakPointsToken }: ImageProps) => { const { sizeToken, src, alt } = getStaticContext(StaticContextProjectCard); - const getImageSize = (sizeToken: SizeToken): ImageSizeToken => { + const getImageSizeWithSizeToken = (sizeToken: SizeToken): ImageSizeToken => { switch (sizeToken) { case 'LARGE': return 'image-100'; @@ -123,12 +138,36 @@ const Image = () => { return 'image-75'; } }; + + const getImageSizeWithBreakPointsToken = ( + breakPointsToken: BreakPointsToken, + ): ImageSizeToken => { + switch (breakPointsToken) { + case 'breakpoint-l': + return 'image-75'; + case 'breakpoint-m': + return 'image-75'; + case 'breakpoint-s': + return 'image-75'; + default: + return 'image-100'; + } + }; + + const sizeTokenValue = ((sizeToken && getImageSizeWithSizeToken(sizeToken)) || + (breakPointsToken && + getImageSizeWithBreakPointsToken(breakPointsToken))) as ImageSizeToken; + return ( ); }; diff --git a/src/components/MainProject/MainProject.css.ts b/src/components/MainProject/MainProject.css.ts index 01cf472..76faa20 100644 --- a/src/components/MainProject/MainProject.css.ts +++ b/src/components/MainProject/MainProject.css.ts @@ -21,8 +21,13 @@ export const wrapStyle = style([ padding: '0 0.69rem', }, [ODSBreakpointTokenVariables['breakpoint-s']]: { - flexDirection: 'column', + position: 'initial', + display: 'grid', + gridTemplateRows: '20rem auto', + rowGap: '4rem', padding: '0', + paddingTop: '1.38rem', + paddingBottom: '2rem', }, }, }, @@ -40,9 +45,8 @@ export const wrapVariants = styleVariants({ minHeight: '20rem', }, [ODSBreakpointTokenVariables['breakpoint-s']]: { - gap: '4rem', height: '100%', - paddingTop: '1.37rem', + minHeight: 'initial', }, }, }, @@ -87,7 +91,8 @@ export const mockWrapVariants = styleVariants({ [ODSBreakpointTokenVariables['breakpoint-s']]: { gap: '0', minWidth: '20rem', - height: '20rem', + minHeight: '20rem', + // height: '20rem', }, }, }, @@ -195,6 +200,8 @@ export const contentWrapStyle = style({ alignItems: 'center', rowGap: '0.5rem', columnGap: '0.5rem', + + height: 'fit-content', }, }, }); diff --git a/src/components/NormalProject/NormalProject.context.ts b/src/components/NormalProject/NormalProject.context.ts index fab54c2..de42d8b 100644 --- a/src/components/NormalProject/NormalProject.context.ts +++ b/src/components/NormalProject/NormalProject.context.ts @@ -7,6 +7,7 @@ export interface ContextDispatchNormalProjectProps { export interface ContextNormalProjectProps { isMouseInSection: boolean; + observerRef: React.RefObject; projectData: ProjectContextData[]; } @@ -18,5 +19,6 @@ export const ContextDispatchNormalProject = export const ContextValueNormalProject = createContext({ isMouseInSection: false, + observerRef: { current: null }, projectData: [], }); diff --git a/src/components/NormalProject/NormalProject.css.ts b/src/components/NormalProject/NormalProject.css.ts index 4da9d17..a314ecc 100644 --- a/src/components/NormalProject/NormalProject.css.ts +++ b/src/components/NormalProject/NormalProject.css.ts @@ -1,4 +1,5 @@ import { globalStyle, style, styleVariants } from '@vanilla-extract/css'; +import { ODSBreakpointTokenVariables } from '@/const/breakpoints'; import { flexCenter } from '@/styles/common/flex.css'; export const wrapStyle = style({ @@ -8,8 +9,13 @@ export const wrapStyle = style({ }); export const defaultContentsStyle = style({ - display: 'flex', - gap: '1.5rem', + // display: 'flex', + // gap: '1.5rem', + // '@media': { + // [ODSBreakpointTokenVariables['breakpoint-s']]: { + // gap: '0.75rem', + // }, + // }, }); export const sliderStyle = style({ @@ -21,6 +27,25 @@ globalStyle('.slick-list', { overflow: 'visible !important', }); +globalStyle('.slick-track', { + display: 'flex', + // gap: '1.5rem', + + // '@media': { + // [ODSBreakpointTokenVariables['breakpoint-s']]: { + // gap: '0.75rem', + // }, + // }, +}); + +globalStyle('.slick-track::before', { + display: 'none', +}); + +globalStyle('.slick-slide', { + // width: 'fit-content !important', +}); + globalStyle('.slick-arrow', { zIndex: 10, }); @@ -41,10 +66,6 @@ const buttonStyle = style([ const buttonAnimationStyle = style({ transition: 'all 0.3s ease-in-out', - // opacity: 0, - // ':hover': { - // opacity: 1, - // }, }); export const buttonVariants = styleVariants({ @@ -52,7 +73,6 @@ export const buttonVariants = styleVariants({ buttonStyle, buttonAnimationStyle, { - // left: '-15rem', left: '0', }, ], @@ -60,13 +80,7 @@ export const buttonVariants = styleVariants({ buttonStyle, buttonAnimationStyle, { - // right: '-15rem', right: '0', - // '@media': { - // [ODSBreakpointTokenVariables['breakpoint-xl']]: { - // right: '0', - // }, - // }, }, ], }); diff --git a/src/components/NormalProject/NormalProject.tsx b/src/components/NormalProject/NormalProject.tsx index f0f78fa..4ea2556 100644 --- a/src/components/NormalProject/NormalProject.tsx +++ b/src/components/NormalProject/NormalProject.tsx @@ -16,11 +16,15 @@ import React, { import Slider from 'react-slick'; import CommonIcon from '@/composable/Icon/CommonIcon'; import { useODSBreakPoints } from '@/hook/useODSBreakPoints'; +import useResizeObserver from '@/hook/useResizeObserver'; import { useWindowResize } from '@/hook/useWindowResize'; import { getPeriod } from '@/utils/date/getPeriod'; +import { getCurrentBreakPoints } from '@/utils/layout/getCurrentBreakPoints'; import ProjectCard from '../Card/Project/ProjectCard'; import { ProjectContextData } from '../Project/Project.context'; import { getButtonPositionWithBreakPoints } from './getButtonPositionWithBreakPoints'; +import { getCardWidthWithBreakPoints } from './getCardWidthWithBreakPoints'; +import { getSlidesToShowWithBreakPoints } from './getSlidesToShowWithBreakPoints'; import { ContextDispatchNormalProject, ContextValueNormalProject, @@ -39,6 +43,7 @@ interface Props { const NormalProject = ({ projectData }: Props) => { const [isMouseInSection, setMouseInSection] = useState(false); + const observerRef = useRef(null); return ( { }} > {projectData.length > 4 ? ( @@ -62,6 +67,7 @@ const NormalProject = ({ projectData }: Props) => { }; const Wrap = ({ children }: PropsWithChildren) => { + const { observerRef } = useContext(ContextValueNormalProject); const { setMouseInSection } = useContext(ContextDispatchNormalProject); const handleMouseEnter = () => { @@ -69,7 +75,11 @@ const Wrap = ({ children }: PropsWithChildren) => { }; return ( -

+
{children}
); @@ -77,6 +87,9 @@ const Wrap = ({ children }: PropsWithChildren) => { const Content = () => { const { projectData } = useContext(ContextValueNormalProject); + + const breakPoints = useODSBreakPoints(); + const currentBreakPoints = getCurrentBreakPoints(breakPoints); return (
<> @@ -93,9 +106,6 @@ const Content = () => { { - + ); })} @@ -118,16 +128,28 @@ const Content = () => { const Slide = () => { const { projectData } = useContext(ContextValueNormalProject); + const breakPoints = useODSBreakPoints(); + const currentBreakPoints = getCurrentBreakPoints(breakPoints); + return ( } - prevArrow={} - speed={500} + slidesToShow={getSlidesToShowWithBreakPoints(currentBreakPoints)} + slidesToScroll={getSlidesToShowWithBreakPoints(currentBreakPoints)} + nextArrow={ + currentBreakPoints !== 'breakpoint-s' ? ( + + ) : undefined + } + prevArrow={ + currentBreakPoints !== 'breakpoint-s' ? ( + + ) : undefined + } + speed={350} > {projectData.map((project, idx) => { if (project.mode === 'MAIN') return null; @@ -139,23 +161,26 @@ const Slide = () => { ); return ( - - - - - - + + + + + + +
); })} @@ -170,17 +195,19 @@ interface ButtonBoxProps { const ButtonBox = (props: ButtonBoxProps) => { const { className, style, onClick } = props; - const buttonRef = useRef(null); + + const { observerRef } = useContext(ContextValueNormalProject); const windowSize = useWindowResize(); const breakPoints = useODSBreakPoints(); + const buttonRef = useRef(null); const shiftValue = getButtonPositionWithBreakPoints(breakPoints); const direction = (className?.split(' ')[1] as 'slick-prev' | 'slick-next') || 'slick-prev'; - const enablePrevPosition = buttonRef.current && direction === 'slick-prev'; - const enableNextPosition = buttonRef.current && direction === 'slick-next'; + const enablePrevPosition = buttonRef.current && direction === 'slick-prev', + enableNextPosition = buttonRef.current && direction === 'slick-next'; const $p = buttonRef.current?.parentElement; const $pp = $p?.parentElement; @@ -195,7 +222,7 @@ const ButtonBox = (props: ButtonBoxProps) => { shiftValue : ''; - useLayoutEffect(() => { + const setButtonPosition = () => { const button = buttonRef.current as HTMLButtonElement; const $p = button.parentElement as HTMLElement; const $pp = $p.parentElement as HTMLElement; @@ -211,7 +238,11 @@ const ButtonBox = (props: ButtonBoxProps) => { const windowEndPoint = -windowSize.width + right; button.style.right = `${windowEndPoint + shiftValue}px`; } - }, [buttonRef]); + }; + + const { resizedValue } = useResizeObserver(observerRef.current, () => {}); + + useLayoutEffect(setButtonPosition, [resizedValue, buttonRef]); return (