Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions app/home/components/introduction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export default function Introduction() {
<div ref={scrollRef} className="relative h-[300vh]">
<div className="sticky top-0 h-screen flex items-center justify-center overflow-hidden">
<ParticleBackground />

<motion.div className="absolute inset-0 z-0 bg-gradient-to-br from-teal-100/10 via-gray-50/10 to-lime-100/10 dark:from-teal-900/10 dark:via-gray-900/10 dark:to-lime-900/10 backdrop-blur-sm" />

<motion.div
Expand All @@ -316,6 +317,47 @@ export default function Introduction() {
새로운 차원
</span>
</h1>

{/* 스크롤 안내 애니메이션 */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 1.5, duration: 0.8 }}
className="mt-8"
>
<motion.div
animate={{ y: [0, 10, 0] }}
transition={{
duration: 2,
repeat: Infinity,
ease: 'easeInOut',
}}
className="flex flex-col items-center text-gray-600 dark:text-gray-400"
>
<span className="text-sm font-medium mb-2">
스크롤하여 더 알아보기
</span>
<motion.div
animate={{ y: [0, 8, 0] }}
transition={{
duration: 1.5,
repeat: Infinity,
ease: 'easeInOut',
}}
className="w-6 h-10 border-2 border-gray-400 dark:border-gray-500 rounded-full flex justify-center"
>
<motion.div
animate={{ y: [0, 12, 0] }}
transition={{
duration: 1.5,
repeat: Infinity,
ease: 'easeInOut',
}}
className="w-1 h-3 bg-gray-400 dark:bg-gray-500 rounded-full mt-2"
/>
</motion.div>
</motion.div>
</motion.div>
Comment on lines +321 to +360

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

스크롤 안내 애니메이션 로직이 Introduction 컴포넌트 내부에 직접 작성되어 있어 가독성과 유지보수성을 저해할 수 있습니다. Introduction 컴포넌트는 이미 크기가 크기 때문에, 이 부분을 별도의 ScrollIndicator 컴포넌트로 분리하는 것을 강력히 권장합니다. 이렇게 하면 코드가 더 모듈화되고 재사용이 용이해집니다.1 컴포넌트명은 ScrollIndicator2, 파일명은 scroll-indicator.tsx3로 명명하는 것이 스타일 가이드에 부합합니다.

또한, 애니메이션에 사용된 수치들(magic numbers)을 상수로 정의하면 코드의 의도를 더 명확하게 파악할 수 있습니다.4

아래는 리팩토링 예시입니다.

ScrollIndicator 컴포넌트 (예: app/home/components/scroll-indicator.tsx에 생성)

import { motion } from 'framer-motion';

// 애니메이션 속성을 상수로 정의하여 가독성 및 유지보수성 향상
const SCROLL_INDICATOR_ANIMATION = {
  WRAPPER: {
    initial: { opacity: 0, y: 20 },
    animate: { opacity: 1, y: 0 },
    transition: { delay: 1.5, duration: 0.8 },
  },
  GROUP: {
    animate: { y: [0, 10, 0] },
    transition: { duration: 2, repeat: Infinity, ease: 'easeInOut' },
  },
  MOUSE_OUTLINE: {
    animate: { y: [0, 8, 0] },
    transition: { duration: 1.5, repeat: Infinity, ease: 'easeInOut' },
  },
  MOUSE_WHEEL: {
    animate: { y: [0, 12, 0] },
    transition: { duration: 1.5, repeat: Infinity, ease: 'easeInOut' },
  },
};

const ScrollIndicator = () => (
  <motion.div
    {...SCROLL_INDICATOR_ANIMATION.WRAPPER}
    className="mt-8"
  >
    <motion.div
      {...SCROLL_INDICATOR_ANIMATION.GROUP}
      className="flex flex-col items-center text-gray-600 dark:text-gray-400"
    >
      <span className="text-sm font-medium mb-2">
        스크롤하여  알아보기
      </span>
      <motion.div
        {...SCROLL_INDICATOR_ANIMATION.MOUSE_OUTLINE}
        className="w-6 h-10 border-2 border-gray-400 dark:border-gray-500 rounded-full flex justify-center"
      >
        <motion.div
          {...SCROLL_INDICATOR_ANIMATION.MOUSE_WHEEL}
          className="w-1 h-3 bg-gray-400 dark:bg-gray-500 rounded-full mt-2"
        />
      </motion.div>
    </motion.div>
  </motion.div>
);

export default ScrollIndicator;

Introduction.tsx 에서 사용법

import ScrollIndicator from './scroll-indicator'; // 경로에 맞게 수정

// ...
            </h1>
            {/* 스크롤 안내 애니메이션 */}
            <ScrollIndicator />
// ...

Style Guide References

Footnotes

  1. 코드는 수정과 확장이 용이해야 합니다. 컴포넌트를 분리하여 유지보수성을 높일 수 있습니다. (link)

  2. 컴포넌트명은 PascalCase를 사용합니다 (예: UserProfile). (link)

  3. 파일명은 kebab-case를 사용합니다 (예: user-profile.tsx). (link)

  4. 상수는 UPPER_SNAKE_CASE를 사용합니다 (예: MAX_VALUE). (link)

</motion.div>

<motion.div
Expand Down