diff --git a/apps/web/src/components/mainpage/coreValue/HorizontalScroll.tsx b/apps/web/src/components/common/HorizontalScroll.tsx similarity index 55% rename from apps/web/src/components/mainpage/coreValue/HorizontalScroll.tsx rename to apps/web/src/components/common/HorizontalScroll.tsx index c49f873..43d693c 100644 --- a/apps/web/src/components/mainpage/coreValue/HorizontalScroll.tsx +++ b/apps/web/src/components/common/HorizontalScroll.tsx @@ -1,7 +1,11 @@ +'use client'; + import clsx from 'clsx'; import { MotionValue, useScroll, useTransform } from 'framer-motion'; import { m } from 'framer-motion'; -import { FC, ReactNode, useEffect, useRef, useState } from 'react'; +import { FC, ReactNode, useRef } from 'react'; + +import useDomInspect from '@/util/useDomInspect'; interface HorizontalScrollProps { className?: string; @@ -13,10 +17,8 @@ const HorizontalScroll: FC = ({ className, children }) => const childrenRef = useRef(null); const { scrollYProgress } = useScroll({ target: containerRef, offset: ['start start', 'end end'] }); - const [childrenWidth, setChildrenWidth] = useState(0); - const [childrenHeight, setChildrenHeight] = useState(0); - const [containerWidth, setContainerWidth] = useState(0); - const [containerHeight, setContainerHeight] = useState(0); + const { width: childrenWidth, height: childrenHeight } = useDomInspect(childrenRef); + const { width: containerWidth, height: containerHeight } = useDomInspect(containerRef); const posX = useTransform(scrollYProgress, [0, 1], [0, containerWidth - childrenWidth]); const posY = useTransform(scrollYProgress, (v) => (v < 1 ? 0 : containerHeight - childrenHeight)); @@ -24,40 +26,6 @@ const HorizontalScroll: FC = ({ className, children }) => const centerLine = useTransform(scrollYProgress, [0, 1], [containerWidth / 2, childrenWidth - containerWidth / 2]); - useEffect(() => { - if (!childrenRef.current) { - return; - } - - const observer = new ResizeObserver((entries) => { - for (const entry of entries) { - setChildrenWidth(entry.contentRect.width); - setChildrenHeight(entry.contentRect.height); - } - }); - observer.observe(childrenRef.current); - return () => { - observer.disconnect(); - }; - }, []); - - useEffect(() => { - if (!containerRef.current) { - return; - } - - const observer = new ResizeObserver((entries) => { - for (const entry of entries) { - setContainerWidth(entry.contentRect.width); - setContainerHeight(entry.contentRect.height); - } - }); - observer.observe(containerRef.current); - return () => { - observer.disconnect(); - }; - }, []); - return (
ReactNode; +} + +interface PositionContext { + width: number; + height: number; + x: number; + y: number; +} + +const InspectableBox: FC = ({ className, children }) => { + const ref = useRef(null); + + const [positionContext, setPositionContext] = useState(null); + + useEffect(() => { + if (!ref.current) { + return; + } + + const observer = new ResizeObserver((entires) => { + if (!ref.current) { + return; + } + + for (const entry of entires) { + setPositionContext({ + height: entry.contentRect.height, + width: entry.contentRect.width, + x: ref.current.offsetLeft, + y: ref.current.offsetTop, + }); + } + }); + + observer.observe(ref.current); + + return () => observer.disconnect(); + }, []); + + return ( +
+ {positionContext && children(positionContext)} +
+ ); +}; + +export default InspectableBox; diff --git a/apps/web/src/components/mainpage/coreValue/CoreValueSection.tsx b/apps/web/src/components/mainpage/coreValue/CoreValueSection.tsx index 3b3d1e8..ae30238 100644 --- a/apps/web/src/components/mainpage/coreValue/CoreValueSection.tsx +++ b/apps/web/src/components/mainpage/coreValue/CoreValueSection.tsx @@ -1,7 +1,11 @@ +'use client'; + import clsx from 'clsx'; -import { FC, ReactNode, useEffect, useRef, useState } from 'react'; +import { FC } from 'react'; + +import HorizontalScroll from '@/components/common/HorizontalScroll'; +import InspectableBox from '@/components/common/InspectableBox'; -import HorizontalScroll from './HorizontalScroll'; import { BaseImage, ConnectionImage, OpportunityImage, OwnershipImage, PleasureImage } from './images'; import ValueCard from './ValueCard'; @@ -18,19 +22,19 @@ const CoreValueSection: FC = ({}) => { VALUE
{cards.map((card, idx) => ( - + {({ x, width }) => ( )} - + ))} -
+
)} @@ -38,67 +42,7 @@ const CoreValueSection: FC = ({}) => { ); }; -interface TrackableProps { - className?: string; - children: (ctx: PositionContext) => ReactNode; -} - -interface PositionContext { - width: number; - height: number; - x: number; - y: number; -} - -const Trackable: FC = ({ className, children }) => { - const ref = useRef(null); - - const [positionContext, setPositionContext] = useState(null); - - useEffect(() => { - if (!ref.current) { - return; - } - - const observer = new ResizeObserver((entires) => { - if (!ref.current) { - return; - } - - for (const entry of entires) { - setPositionContext({ - height: entry.contentRect.height, - width: entry.contentRect.width, - x: ref.current.offsetLeft, - y: ref.current.offsetTop, - }); - } - }); - - observer.observe(ref.current); - - return () => observer.disconnect(); - }, []); - - return ( -
- {positionContext && children(positionContext)} -
- ); -}; - -interface CardBaseProps { - className?: string; - children?: ReactNode; -} - -const DescriptionCard: FC = ({ className, children }) => { - return ( -
- {children} -
- ); -}; +const descriptionStyles = 'flex h-full w-full items-center justify-center whitespace-pre-line text-center'; const cards = [ { @@ -106,12 +50,12 @@ const cards = [ name: '오너십', image: , description: ( - +
{`주체적인 책임감으로 스스로 필요한 가치를 발견하고, 모두가 앞으로 나아가는 추진력을 경험합니다.`} - +
), }, { @@ -119,11 +63,11 @@ const cards = [ name: '연결', image: , description: ( - +
{`자유로운 네트워킹 환경 속 뛰어난 동료와 깊이 연결되는 경험을 할 수 있습니다.`} - +
), }, { @@ -131,11 +75,11 @@ const cards = [ name: '기반', image: , description: ( - +
{`조직의 단단한 기반으로써, 성장에 필요한 믿음직한 발판을 제공합니다.`} - +
), }, { @@ -143,12 +87,12 @@ const cards = [ name: '기회', image: , description: ( - +
{`지속적인 경험을 통해 시야를 확장하고, 더 넓고 새로운 경험의 기회를 선사합니다.`} - +
), }, { @@ -156,12 +100,12 @@ const cards = [ name: '즐거움', image: , description: ( - +
{`존중을 기반으로, 진정으로 모두가 즐겁게 스스로의 목표를 세우고 이루는 경험을 선사합니다.`} - +
), }, ]; diff --git a/apps/web/src/components/mainpage/coreValue/ValueCard.tsx b/apps/web/src/components/mainpage/coreValue/ValueCard.tsx index 5f78e83..c392059 100644 --- a/apps/web/src/components/mainpage/coreValue/ValueCard.tsx +++ b/apps/web/src/components/mainpage/coreValue/ValueCard.tsx @@ -16,12 +16,9 @@ interface ValueCardProps { description: ReactNode; seq: number; centerLineProgress: MotionValue; - center: number; + flipRange: [number, number]; } -const OPEN_DELTA = 400; -const KEEP_DELTA = 200; - const ValueCard: FC = ({ className, image, @@ -29,14 +26,10 @@ const ValueCard: FC = ({ name, description, seq, - center, + flipRange, centerLineProgress, }) => { - const flip = useTransform( - centerLineProgress, - [center - OPEN_DELTA, center - KEEP_DELTA, center + KEEP_DELTA, center + OPEN_DELTA], - [0, 1, 1, 0], - ); + const flip = useTransform(centerLineProgress, flipRange, [0, 1]); const formattedSeq = `${seq}`.padStart(2, '0'); @@ -49,9 +42,7 @@ const ValueCard: FC = ({
{image}
{keyword} - - {name} {center} - + {name}
) => { + const [positionContext, setPositionContext] = useState({ + height: 0, + width: 0, + x: 0, + y: 0, + }); + + useEffect(() => { + if (!ref.current) { + return; + } + + const observer = new ResizeObserver((entries) => { + if (!ref.current) { + return; + } + + for (const entry of entries) { + setPositionContext({ + height: entry.contentRect.height, + width: entry.contentRect.width, + x: ref.current.offsetLeft, + y: ref.current.offsetTop, + }); + } + }); + observer.observe(ref.current); + return () => { + observer.disconnect(); + }; + }, [ref]); + + return positionContext; +}; + +export default useDomInspect;