Skip to content

Commit

Permalink
refactor: 함수 분리
Browse files Browse the repository at this point in the history
  • Loading branch information
Tekiter committed Jul 25, 2023
1 parent ff854df commit ddcb735
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 129 deletions.
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -13,51 +17,15 @@ const HorizontalScroll: FC<HorizontalScrollProps> = ({ className, children }) =>
const childrenRef = useRef<HTMLDivElement>(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));
const innerBoxPosition = useTransform(scrollYProgress, (v) => (v <= 0 || v >= 1 ? 'static' : 'fixed'));

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 (
<div ref={containerRef} className={clsx('w-full overflow-x-hidden', className)}>
<m.div
Expand Down
54 changes: 54 additions & 0 deletions apps/web/src/components/common/InspectableBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
'use client';

import { FC, ReactNode, useEffect, useRef, useState } from 'react';

interface InspectableBoxProps {
className?: string;
children: (ctx: PositionContext) => ReactNode;
}

interface PositionContext {
width: number;
height: number;
x: number;
y: number;
}

const InspectableBox: FC<InspectableBoxProps> = ({ className, children }) => {
const ref = useRef<HTMLDivElement>(null);

const [positionContext, setPositionContext] = useState<PositionContext | null>(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 (
<div ref={ref} className={className}>
{positionContext && children(positionContext)}
</div>
);
};

export default InspectableBox;
98 changes: 21 additions & 77 deletions apps/web/src/components/mainpage/coreValue/CoreValueSection.tsx
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -18,150 +22,90 @@ const CoreValueSection: FC<CoreValueSectionProps> = ({}) => {
<span>VALUE</span>
</div>
{cards.map((card, idx) => (
<Trackable key={card.keyword}>
<InspectableBox key={card.keyword}>
{({ x, width }) => (
<ValueCard
className='h-[52rem] w-[36.8rem]'
{...card}
seq={idx + 1}
centerLineProgress={centerLine}
center={x + width / 2}
flipRange={[x - width / 2, x + width / 2]}
/>
)}
</Trackable>
</InspectableBox>
))}
<div className='w-[70vw]' />
<div className='w-[50vw]' />
</div>
</div>
)}
</HorizontalScroll>
);
};

interface TrackableProps {
className?: string;
children: (ctx: PositionContext) => ReactNode;
}

interface PositionContext {
width: number;
height: number;
x: number;
y: number;
}

const Trackable: FC<TrackableProps> = ({ className, children }) => {
const ref = useRef<HTMLDivElement>(null);

const [positionContext, setPositionContext] = useState<PositionContext | null>(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 (
<div ref={ref} className={className}>
{positionContext && children(positionContext)}
</div>
);
};

interface CardBaseProps {
className?: string;
children?: ReactNode;
}

const DescriptionCard: FC<CardBaseProps> = ({ className, children }) => {
return (
<div className={clsx('flex h-full w-full items-center justify-center whitespace-pre-line text-center', className)}>
{children}
</div>
);
};
const descriptionStyles = 'flex h-full w-full items-center justify-center whitespace-pre-line text-center';

const cards = [
{
keyword: 'Ownership',
name: '오너십',
image: <OwnershipImage />,
description: (
<DescriptionCard className='bg-brand-orange text-orange-sub'>
<div className={clsx(descriptionStyles, 'bg-brand-orange text-orange-sub')}>
{`주체적인 책임감으로
스스로 필요한 가치를 발견하고,
모두가 앞으로 나아가는
추진력을 경험합니다.`}
</DescriptionCard>
</div>
),
},
{
keyword: 'Connection',
name: '연결',
image: <ConnectionImage />,
description: (
<DescriptionCard className='bg-brand-skyblue text-skyblue-sub'>
<div className={clsx(descriptionStyles, 'bg-brand-skyblue text-skyblue-sub')}>
{`자유로운 네트워킹 환경 속
뛰어난 동료와 깊이 연결되는
경험을 할 수 있습니다.`}
</DescriptionCard>
</div>
),
},
{
keyword: 'Base',
name: '기반',
image: <BaseImage />,
description: (
<DescriptionCard className='bg-brand-blue text-blue-sub'>
<div className={clsx(descriptionStyles, 'bg-brand-blue text-blue-sub')}>
{`조직의 단단한 기반으로써,
성장에 필요한 믿음직한 발판을
제공합니다.`}
</DescriptionCard>
</div>
),
},
{
keyword: 'Opportunity',
name: '기회',
image: <OpportunityImage />,
description: (
<DescriptionCard className='bg-brand-pink text-pink-sub'>
<div className={clsx(descriptionStyles, 'bg-brand-pink text-pink-sub')}>
{`지속적인 경험을 통해
시야를 확장하고,
더 넓고 새로운 경험의
기회를 선사합니다.`}
</DescriptionCard>
</div>
),
},
{
keyword: 'Pleasure',
name: '즐거움',
image: <PleasureImage />,
description: (
<DescriptionCard className='bg-brand-yellow text-yellow-sub'>
<div className={clsx(descriptionStyles, 'bg-brand-yellow text-yellow-sub')}>
{`존중을 기반으로,
진정으로 모두가 즐겁게
스스로의 목표를 세우고
이루는 경험을 선사합니다.`}
</DescriptionCard>
</div>
),
},
];
Expand Down
17 changes: 4 additions & 13 deletions apps/web/src/components/mainpage/coreValue/ValueCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,20 @@ interface ValueCardProps {
description: ReactNode;
seq: number;
centerLineProgress: MotionValue<number>;
center: number;
flipRange: [number, number];
}

const OPEN_DELTA = 400;
const KEEP_DELTA = 200;

const ValueCard: FC<ValueCardProps> = ({
className,
image,
keyword,
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');

Expand All @@ -49,9 +42,7 @@ const ValueCard: FC<ValueCardProps> = ({
<div className=''>{image}</div>
<div className='flex flex-1 flex-col items-center justify-center'>
<span className={clsx(orbitron.className, 'text-[3.6rem] font-bold leading-[100%]')}>{keyword}</span>
<span className='mt-[2rem] text-[2.8rem] font-semibold'>
{name} {center}
</span>
<span className='mt-[2rem] text-[2.8rem] font-semibold'>{name}</span>
</div>
<div
className={clsx(
Expand Down
46 changes: 46 additions & 0 deletions apps/web/src/util/useDomInspect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { RefObject, useEffect, useState } from 'react';

interface PositionContext {
width: number;
height: number;
x: number;
y: number;
}

const useDomInspect = (ref: RefObject<HTMLElement>) => {
const [positionContext, setPositionContext] = useState<PositionContext>({
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;

0 comments on commit ddcb735

Please sign in to comment.