Skip to content

Conversation

@yshls
Copy link
Collaborator

@yshls yshls commented Aug 6, 2025

📝 변경 사항

🔍 변경 사항 세부 설명

🕵️‍♀️ 요청사항

📷 스크린샷 (선택)

@github-actions github-actions bot enabled auto-merge August 6, 2025 06:59
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @yshls, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a new interactive service introduction banner to the homepage. Its primary purpose is to provide users with a dynamic and engaging overview of the service's core values, key features, and available trading styles, enhancing the initial user experience and information accessibility.

Highlights

  • New Service Introduction Component: I've added a new Introduction component (app/home/components/introduction.tsx) that serves as a dynamic, multi-slide banner to showcase the service's key aspects.
  • Homepage Integration: The HomePage.tsx file has been updated to import and render this new Introduction component directly below the existing Banner, ensuring it's prominently displayed on the main page.
  • Interactive UI/UX: The Introduction component features an auto-playing carousel with manual navigation (arrows, drag gestures, and pagination dots), leveraging framer-motion for smooth transitions and animations, enhancing user engagement.
  • Rich Content Display: The banner supports various slide types, including a hero section, core values, key features, and different trade styles, each with dedicated layouts and icons (from lucide-react), allowing for comprehensive information delivery.
  • Dependency Updates: I've updated framer-motion and added lucide-react and react-intersection-observer to the project dependencies to support the new component's functionality and styling.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments or fill out our survey to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@yshls yshls added the STYLE css 스타일 조정 label Aug 6, 2025
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

이번 PR은 서비스 소개 배너 컴포넌트를 추가하는 내용이네요. 전반적으로 잘 작성되었지만, 몇 가지 개선점을 제안합니다.

주요 피드백은 다음과 같습니다:

  • 네이밍 컨벤션: 컴포넌트와 상수의 이름을 스타일 가이드에 맞게 수정하여 일관성을 높였습니다.
  • 코드 가독성: 매직 넘버를 상수로 추출하여 코드의 의도를 명확히 하도록 제안했습니다.
  • 웹 접근성: 키보드 사용자와 스크린 리더 사용자를 위해 페이지네이션 UI를 개선했습니다.
  • 최신 기술 적용: Next.js의 Image 컴포넌트에서 deprecated된 prop을 최신 방식으로 수정했습니다.
  • 스타일 가이드 준수: import 순서와 JSDoc 작성 등 스타일 가이드를 준수하도록 수정 제안을 포함했습니다.

자세한 내용은 각 파일의 리뷰 코멘트를 참고해주세요.

Comment on lines +321 to +326
src={style.visual}
alt={style.title}
layout="fill"
objectFit="contain"
/>
</div>

Choose a reason for hiding this comment

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

high

next/image 컴포넌트의 layoutobjectFit prop은 Next.js 최신 버전에서 deprecated 되었습니다. layout="fill" 대신 fill prop을 boolean 값으로 사용하고, objectFitstyle prop으로 옮겨야 합니다.

                  <Image
                    src={style.visual}
                    alt={style.title}
                    fill
                    style={{ objectFit: 'contain' }}
                  />

Comment on lines +3 to +17
import React, { useState, useEffect, useCallback } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import Image from 'next/image';
import {
Newspaper,
Zap,
Clock,
CreditCard,
ShieldCheck,
Users,
ArrowLeft,
ArrowRight,
LogIn, // LogIn 아이콘 import
} from 'lucide-react';

Choose a reason for hiding this comment

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

medium

스타일 가이드에 따라 import 구문을 그룹화하고 정렬해야 합니다.1 React 관련 import를 먼저, 그 다음 외부 라이브러리, 그리고 내부 모듈 순으로 정렬하는 것이 좋습니다. 각 그룹 내에서는 알파벳 순으로 정렬해주세요. 또한, named import 목록도 알파벳 순으로 정렬하는 것이 좋습니다.

import React, { useCallback, useEffect, useState } from 'react';
import { AnimatePresence, motion } from 'framer-motion';
import { 
  ArrowLeft,
  ArrowRight,
  Clock,
  CreditCard,
  Lock,
  LogIn, // LogIn 아이콘 import
  Newspaper,
  ShieldCheck,
  Users,
  Zap,
} from 'lucide-react';
import Image from 'next/image';

Style Guide References

Footnotes

  1. 임포트는 React, 외부 라이브러리, 내부 모듈, 상대 경로 순으로 그룹화하고 각 그룹 내에서 알파벳 순으로 정렬해야 합니다. (link)


// --- 슬라이드 데이터 ---
const slides: Slide[] = [
{

Choose a reason for hiding this comment

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

medium

스타일 가이드에 따라, 상수 slidesUPPER_SNAKE_CASESLIDES로 명명하는 것이 좋습니다.1 코드 내에서 slides를 사용하는 모든 곳(146, 192, 214라인)도 함께 수정해야 합니다.

const SLIDES: Slide[] = [

Style Guide References

Footnotes

  1. 상수는 UPPER_SNAKE_CASE를 사용하여 선언해야 합니다. (link)


// --- 메인 배너 컴포넌트 ---
export default function Banner() {
const [[page, direction], setPage] = useState([0, 0]);

Choose a reason for hiding this comment

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

medium

컴포넌트의 이름이 파일명(introduction.tsx) 및 HomePage.tsx에서의 import 이름(Introduction)과 일치하지 않습니다. 현재 Banner로 되어 있는데, 일관성을 위해 Introduction으로 변경하는 것이 좋겠습니다. 이는 코드의 가독성과 유지보수성을 높여줍니다.1

또한, 스타일 가이드에 따라 공개된 모든 함수와 컴포넌트에는 JSDoc 주석을 작성해야 합니다.2 이 컴포넌트의 목적, props 등에 대한 설명을 JSDoc 형식으로 추가하면 코드 이해에 도움이 됩니다.

/**
 * 서비스의 핵심 가치와 기능을 소개하는 슬라이드 배너 컴포넌트입니다.
 */
export default function Introduction() {

Style Guide References

Footnotes

  1. 모든 프로젝트에서 일관된 스타일을 유지하여 협업을 개선해야 합니다. (link)

  2. 모든 공개 함수와 클래스에 대해 JSDoc을 작성해야 합니다. (link)

const interval = setInterval(() => {
paginate(1);
}, 5000);
return () => clearInterval(interval);

Choose a reason for hiding this comment

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

medium

자동 슬라이드 간격 5000이 매직 넘버로 사용되고 있습니다. 가독성과 유지보수성을 위해 의미를 명확히 나타내는 상수로 추출하여 사용하는 것을 권장합니다. (예: const AUTO_SLIDE_INTERVAL = 5000;)

const slideIndex = ((page % slides.length) + slides.length) % slides.length;

const variants = {
enter: (direction: number) => ({

Choose a reason for hiding this comment

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

medium

스타일 가이드에 따라, 상수 variantsUPPER_SNAKE_CASEVARIANTS로 명명하는 것이 좋습니다.1 코드 내에서 variants를 사용하는 곳(171라인)도 함께 수정해야 합니다.

const VARIANTS = {

Style Guide References

Footnotes

  1. 상수는 UPPER_SNAKE_CASE를 사용하여 선언해야 합니다. (link)

Comment on lines +184 to +188
paginate(1);
} else if (swipe > 10000) {
paginate(-1);
}
}}

Choose a reason for hiding this comment

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

medium

스와이프 감지를 위한 임계값 10000이 매직 넘버로 사용되고 있습니다. const SWIPE_CONFIDENCE_THRESHOLD = 10000;과 같이 상수로 정의하면 코드의 의도를 더 명확하게 전달할 수 있습니다.

Comment on lines +215 to +221
key={i}
onClick={() => setPage([i, i > slideIndex ? 1 : -1])}
className={`h-2 w-2 rounded-full cursor-pointer transition-all duration-300 ${
slideIndex === i ? 'w-6 bg-teal-green' : 'bg-gray-400'
}`}
/>
))}

Choose a reason for hiding this comment

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

medium

페이지네이션 인디케이터로 사용되는 div 요소는 onClick 핸들러를 가지고 있지만 키보드로는 접근할 수 없으며 스크린 리더 사용자에게 적절한 정보를 제공하지 않습니다. 웹 접근성을 향상시키기 위해 div 대신 button 요소를 사용하거나, divrole="button", tabIndex="0", 그리고 키보드 이벤트 핸들러(onKeyDown)를 추가하는 것을 고려해주세요.

          <button
            key={i}
            onClick={() => setPage([i, i > slideIndex ? 1 : -1])}
            className={`h-2 w-2 rounded-full cursor-pointer transition-all duration-300 ${
              slideIndex === i ? 'w-6 bg-teal-green' : 'bg-gray-400'
            }`}
            aria-label={`${i + 1}번 슬라이드로 이동`}
            aria-current={slideIndex === i}
          />

@github-actions github-actions bot merged commit 43d4e76 into main Aug 6, 2025
2 checks passed
@yshls
Copy link
Collaborator Author

yshls commented Aug 6, 2025


@yshls
Copy link
Collaborator Author

yshls commented Aug 6, 2025

/gemini review

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

안녕하세요. 서비스 소개 배너 기능 추가 PR 리뷰입니다. 전반적으로 framer-motion을 활용하여 동적인 캐러셀 컴포넌트를 잘 구현하셨습니다. 다만, 코드의 유지보수성과 가독성을 높이기 위한 몇 가지 개선점을 제안합니다. 주요 내용으로는 스타일 가이드 준수, 매직 넘버 상수화, deprecated된 next/image prop 교체 등이 있습니다. 또한, 새로 추가된 컴포넌트가 실제 페이지에 적용되지 않은 부분과 사용하지 않는 의존성이 추가된 점도 확인이 필요해 보입니다. 자세한 내용은 각 코드 라인에 남긴 코멘트를 참고해주세요.

];

// --- 메인 배너 컴포넌트 ---
export default function Banner() {

Choose a reason for hiding this comment

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

high

새로 추가된 Banner 컴포넌트가 애플리케이션 내에서 사용되고 있지 않은 것 같습니다. PR의 핵심 기능이므로 HomePage 컴포넌트 등 적절한 위치에 추가해야 합니다.

또한, 파일 이름은 introduction.tsx인데 컴포넌트 이름은 Banner로 되어 있어 혼동을 줄 수 있습니다. PR의 제목('서비스 소개 배너')과 파일의 역할을 고려하여 IntroductionBanner와 같이 좀 더 명확한 이름으로 변경하는 것을 제안합니다.

@@ -0,0 +1,335 @@
'use client';

Choose a reason for hiding this comment

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

medium

컴포넌트 파일의 크기가 300줄을 초과하여 다소 큽니다. 가독성과 유지보수성을 높이기 위해 다음과 같이 파일을 분리하는 것을 고려해 보세요.

  • introduction.types.ts: 타입 정의
  • introduction.data.ts: slides 데이터
  • slide-content.tsx: SlideContent 컴포넌트

type Slide = HeroSlide | CoreValuesSlide | FeaturesSlide | TradeStylesSlide;

// --- 슬라이드 데이터 ---
const slides: Slide[] = [

Choose a reason for hiding this comment

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

medium

스타일 가이드에 따르면 상수는 UPPER_SNAKE_CASE로 작성해야 합니다.1 slidesSLIDES로 변경하는 것을 제안합니다.

const SLIDES: Slide[] = [

Style Guide References

Footnotes

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


// --- 메인 배너 컴포넌트 ---
export default function Banner() {
const [[page, direction], setPage] = useState([0, 0]);

Choose a reason for hiding this comment

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

medium

[[page, direction], setPage]와 같은 배열 비구조화 할당은 간결하지만, 처음 보는 개발자에게는 상태의 의미를 파악하기 어려울 수 있습니다. 상태를 객체로 관리하거나 두 개의 useState로 분리하면 가독성을 높일 수 있습니다.

제안 1: 상태 객체 사용

const [slideState, setSlideState] = useState({ page: 0, direction: 0 });

제안 2: 개별 상태 사용

const [page, setPage] = useState(0);
const [direction, setDirection] = useState(0);

useEffect(() => {
const interval = setInterval(() => {
paginate(1);
}, 5000);

Choose a reason for hiding this comment

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

medium

코드 내에 5000, 1000, 10000과 같은 매직 넘버가 여러 곳에서 사용되고 있습니다. 가독성과 유지보수성을 높이기 위해 이 값들을 의미 있는 이름의 상수로 정의하여 사용하는 것을 권장합니다.

예시:

const AUTO_SLIDE_INTERVAL = 5000;
const SWIPE_THRESHOLD = 10000;
const ANIMATION_OFFSET = 1000;

Comment on lines +320 to +325
<Image
src={style.visual}
alt={style.title}
layout="fill"
objectFit="contain"
/>

Choose a reason for hiding this comment

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

medium

next/image 컴포넌트의 layoutobjectFit prop은 Next.js 최신 버전에서 deprecated 되었습니다. fill prop과 style prop을 사용하는 방식으로 변경하는 것이 좋습니다.

                  <Image
                    src={style.visual}
                    alt={style.title}
                    fill
                    style={{ objectFit: 'contain' }}
                  />

"prismjs": "^1.30.0",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-intersection-observer": "^9.16.0",

Choose a reason for hiding this comment

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

medium

react-intersection-observer 패키지가 추가되었지만, 현재 PR에서 추가된 코드에서는 사용되지 않고 있습니다. 만약 의도된 것이 아니라면 불필요한 의존성을 제거하는 것이 좋습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

STYLE css 스타일 조정

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants