-
Notifications
You must be signed in to change notification settings - Fork 1
Feat/45-2 메인페이지 인기 체험 섹션 UI 구현 #72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Walkthrough이 변경 사항은 기존 BannerSection과 SearchBar 컴포넌트의 최대 너비를 확장하며, 새로운 ExperienceCard 및 PopularExperiences 컴포넌트를 추가합니다. 또한, PopularExperiences를 홈 페이지에 배치하고, 스크롤바를 숨기는 글로벌 CSS 유틸리티 클래스를 도입합니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant HomePage
participant BannerSection
participant PopularExperiences
participant ExperienceCard
User->>HomePage: 페이지 접속
HomePage->>BannerSection: 배너 렌더링
HomePage->>PopularExperiences: 인기 체험 슬라이더 렌더링
PopularExperiences->>ExperienceCard: 각 카드 렌더링 (4개)
User->>PopularExperiences: 좌/우 화살표 클릭
PopularExperiences->>PopularExperiences: 슬라이더 스크롤 이동
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
src/app/(with-header)/components/PopularExperiences.tsxOops! Something went wrong! :( ESLint: 9.30.1 ESLint couldn't find the plugin "eslint-plugin-react-hooks". (The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following: The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/[email protected][email protected][email protected][email protected]/node_modules/eslint-config-next/index.js". If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting. src/app/(with-header)/components/SearchBar.tsxOops! Something went wrong! :( ESLint: 9.30.1 ESLint couldn't find the plugin "eslint-plugin-react-hooks". (The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following: The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/[email protected][email protected][email protected][email protected]/node_modules/eslint-config-next/index.js". If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting. src/app/(with-header)/components/BannerSection.tsxOops! Something went wrong! :( ESLint: 9.30.1 ESLint couldn't find the plugin "eslint-plugin-react-hooks". (The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following: The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/[email protected][email protected][email protected][email protected]/node_modules/eslint-config-next/index.js". If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting.
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (6)
src/app/(with-header)/components/BannerSection.tsx(1 hunks)src/app/(with-header)/components/ExperienceCard.tsx(1 hunks)src/app/(with-header)/components/PopularExperiences.tsx(1 hunks)src/app/(with-header)/components/SearchBar.tsx(1 hunks)src/app/(with-header)/page.tsx(1 hunks)src/app/globals.css(1 hunks)
🔇 Additional comments (10)
src/app/globals.css (1)
135-141: 스크롤바를 숨길 때, 키보드·스크린리더 사용성까지 함께 고려해주세요
.no-scrollbar은 시각적으론 깔끔하지만, 스크롤이 존재함을 인지하지 못해 키보드 사용자·스크린리더 사용자가 컨텐츠 접근에 어려움을 겪을 수 있습니다.
- 컨테이너에
role="region"또는aria-label을 부여해 영역의 존재를 알리거나,- 포커스가 진입하면
outline을 주어 스크롤이 가능한 영역임을 시각적으로 표시하는 방안을 포함해 보세요.
[ suggest_optional_refactor ]src/app/(with-header)/components/BannerSection.tsx (1)
20-20: max-width 확장은 문제 없어 보입니다
lg:max-w-1200조정으로 SearchBar와 동일한 그리드 폭을 유지해 일관성이 향상되었습니다.
[ approve_code_changes ]src/app/(with-header)/components/SearchBar.tsx (1)
16-16: 폭 조정 반영 확인 완료
홈 상단 배너와 동일 폭(1200px)으로 맞춰졌습니다. 별도 문제 없습니다.
[ approve_code_changes ]src/app/(with-header)/page.tsx (1)
2-9: 초기 번들 사이즈를 줄이기 위해 PopularExperiences를 지연 로딩할 것을 권장합니다
홈 진입 시 반드시 필요한 섹션이 아니라면,next/dynamic을 사용해 클라이언트 측에서 Lazy-load 하면 퍼포먼스를 이득 볼 수 있습니다.-import PopularExperiences from '@/app/(with-header)/components/PopularExperiences'; +import dynamic from 'next/dynamic'; +const PopularExperiences = dynamic( + () => import('@/app/(with-header)/components/PopularExperiences'), + { ssr: false } +);[ suggest_optional_refactor ]
src/app/(with-header)/components/ExperienceCard.tsx (4)
5-6: Tailwind 임의 값 사용법 오류 – 빌드 시 클래스가 무시됩니다
w-186,h-186,md:w-384등은 Tailwind 기본 스케일에 존재하지 않는 클래스입니다. 임의 픽셀값을 쓰려면 대괄호 표기법을 사용해야 합니다.-<div className='relative w-186 h-186 md:w-384 md:h-384 rounded-[20px] overflow-hidden shadow-md bg-white'> +<div className='relative w-[186px] h-[186px] md:w-[384px] md:h-[384px] rounded-[20px] overflow-hidden shadow-md bg-white'>적용하지 않으면 해당 크기 클래스가 제거되어 의도한 레이아웃이 깨집니다.
[ raise_critical_issue ]
8-12: 정적 이미지·텍스트 하드코딩 → 재사용성 급격히 저하
현재 컴포넌트는 카드 내용이 고정되어 있어 추후 API 연동 시 다시 수정해야 합니다.src,alt,title,price,rating등을props로 받아 재사용 가능하도록 리팩터링을 권장합니다.
[ suggest_essential_refactor ]
18-19: 별점 문구의 접근성 개선이 필요합니다
텍스트 앞의⭐emoji만으로는 스크린리더가 의미를 충분히 설명하지 못합니다.
예)<span aria-label="평점 4.9점, 리뷰 293개">⭐ 4.9 (293)</span>처럼aria-label을 추가해 주세요.
[ suggest_optional_refactor ]
20-22: 어두운 배경 위 회색 글씨는 대비가 부족할 수 있습니다
text-gray-600은 RGBA 대비 기준 WCAG AA를 충족하지 못할 가능성이 높습니다. 브랜드 가이드에 맞는 더 밝은 색상(예:text-gray-300)을 검토해 주세요.
[ request_verification ]src/app/(with-header)/components/PopularExperiences.tsx (2)
1-7: 임포트 구조가 깔끔하고 올바릅니다.클라이언트 사이드 기능을 위한 'use client' 지시어 사용이 적절하고, 임포트 경로와 구조가 잘 정리되어 있습니다.
8-11: 컴포넌트 선언과 ref 설정이 적절합니다.TypeScript 타이핑이 정확하고 ref 사용 목적이 명확하게 주석으로 설명되어 있습니다.
| const scrollByCard = (direction: 'left' | 'right') => { | ||
| if (!sliderRef.current) return; | ||
|
|
||
| // 첫 번째 카드 요소를 찾아서 너비 측정 | ||
| const card = sliderRef.current.querySelector('.card'); | ||
| if (!(card instanceof HTMLElement)) return; | ||
|
|
||
| const cardWidth = card.offsetWidth; // 카드 너비 | ||
| const gap = parseInt(getComputedStyle(sliderRef.current).gap) || 0; // gap 값 | ||
| const distance = cardWidth + gap; // 한 번에 이동할 거리 | ||
|
|
||
| // 슬라이더 스크롤 이동 (좌/우 방향에 따라) | ||
| sliderRef.current.scrollBy({ | ||
| left: direction === 'left' ? -distance : distance, | ||
| behavior: 'smooth', | ||
| }); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
스크롤 함수의 안정성을 개선하세요.
함수가 전반적으로 잘 구현되어 있지만 몇 가지 개선 사항이 있습니다:
parseInt에서 NaN 처리가 필요합니다.card클래스에 의존하는 구조로 인한 결합도가 높습니다
다음과 같이 개선할 수 있습니다:
const scrollByCard = (direction: 'left' | 'right') => {
if (!sliderRef.current) return;
const card = sliderRef.current.querySelector('.card');
if (!(card instanceof HTMLElement)) return;
const cardWidth = card.offsetWidth;
- const gap = parseInt(getComputedStyle(sliderRef.current).gap) || 0;
+ const gapValue = getComputedStyle(sliderRef.current).gap;
+ const gap = gapValue ? parseInt(gapValue) || 0 : 0;
const distance = cardWidth + gap;
sliderRef.current.scrollBy({
left: direction === 'left' ? -distance : distance,
behavior: 'smooth',
});
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const scrollByCard = (direction: 'left' | 'right') => { | |
| if (!sliderRef.current) return; | |
| // 첫 번째 카드 요소를 찾아서 너비 측정 | |
| const card = sliderRef.current.querySelector('.card'); | |
| if (!(card instanceof HTMLElement)) return; | |
| const cardWidth = card.offsetWidth; // 카드 너비 | |
| const gap = parseInt(getComputedStyle(sliderRef.current).gap) || 0; // gap 값 | |
| const distance = cardWidth + gap; // 한 번에 이동할 거리 | |
| // 슬라이더 스크롤 이동 (좌/우 방향에 따라) | |
| sliderRef.current.scrollBy({ | |
| left: direction === 'left' ? -distance : distance, | |
| behavior: 'smooth', | |
| }); | |
| }; | |
| const scrollByCard = (direction: 'left' | 'right') => { | |
| if (!sliderRef.current) return; | |
| // 첫 번째 카드 요소를 찾아서 너비 측정 | |
| const card = sliderRef.current.querySelector('.card'); | |
| if (!(card instanceof HTMLElement)) return; | |
| const cardWidth = card.offsetWidth; // 카드 너비 | |
| const gapValue = getComputedStyle(sliderRef.current).gap; | |
| const gap = gapValue ? parseInt(gapValue) || 0 : 0; | |
| const distance = cardWidth + gap; // 한 번에 이동할 거리 | |
| // 슬라이더 스크롤 이동 (좌/우 방향에 따라) | |
| sliderRef.current.scrollBy({ | |
| left: direction === 'left' ? -distance : distance, | |
| behavior: 'smooth', | |
| }); | |
| }; |
🤖 Prompt for AI Agents
In src/app/(with-header)/components/PopularExperiences.tsx around lines 13 to
29, improve the scrollByCard function by adding a check to handle NaN results
from parseInt when reading the gap style, defaulting to 0 if NaN. Also, reduce
coupling by avoiding direct dependency on the '.card' class; instead, consider
passing the card element or its width as a parameter or using a more flexible
selector strategy. Implement these changes to enhance function stability and
maintainability.
| return ( | ||
| <section className='pt-24 md:pt-34 pl-24 lg:pl-0 pb-40 lg:pb-33 lg:max-w-1200 lg:w-full mx-auto'> | ||
| {/* 섹션 제목 + 좌우 화살표 버튼 */} | ||
| <div className='flex justify-between items-center pb-16 md:pb-32 mb-6'> | ||
| <h2 className='text-xl md:text-3xl font-bold'>🔥 인기 체험</h2> | ||
| <div className='flex gap-2'> | ||
| <IconArrowLeft size={32} onClick={() => scrollByCard('left')} className='text-2xl px-3' /> | ||
| <IconArrowRight size={32} onClick={() => scrollByCard('right')} className='text-2xl px-3' /> | ||
| </div> | ||
| </div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
접근성 개선이 필요합니다.
화살표 아이콘을 클릭 가능한 요소로 사용하고 있지만 접근성 지원이 부족합니다.
다음과 같이 개선하세요:
<div className='flex gap-2'>
- <IconArrowLeft size={32} onClick={() => scrollByCard('left')} className='text-2xl px-3' />
- <IconArrowRight size={32} onClick={() => scrollByCard('right')} className='text-2xl px-3' />
+ <button
+ onClick={() => scrollByCard('left')}
+ className='text-2xl px-3 focus:outline-none focus:ring-2 focus:ring-blue-500 rounded'
+ aria-label='이전 체험 보기'
+ >
+ <IconArrowLeft size={32} />
+ </button>
+ <button
+ onClick={() => scrollByCard('right')}
+ className='text-2xl px-3 focus:outline-none focus:ring-2 focus:ring-blue-500 rounded'
+ aria-label='다음 체험 보기'
+ >
+ <IconArrowRight size={32} />
+ </button>
</div>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| return ( | |
| <section className='pt-24 md:pt-34 pl-24 lg:pl-0 pb-40 lg:pb-33 lg:max-w-1200 lg:w-full mx-auto'> | |
| {/* 섹션 제목 + 좌우 화살표 버튼 */} | |
| <div className='flex justify-between items-center pb-16 md:pb-32 mb-6'> | |
| <h2 className='text-xl md:text-3xl font-bold'>🔥 인기 체험</h2> | |
| <div className='flex gap-2'> | |
| <IconArrowLeft size={32} onClick={() => scrollByCard('left')} className='text-2xl px-3' /> | |
| <IconArrowRight size={32} onClick={() => scrollByCard('right')} className='text-2xl px-3' /> | |
| </div> | |
| </div> | |
| return ( | |
| <section className='pt-24 md:pt-34 pl-24 lg:pl-0 pb-40 lg:pb-33 lg:max-w-1200 lg:w-full mx-auto'> | |
| {/* 섹션 제목 + 좌우 화살표 버튼 */} | |
| <div className='flex justify-between items-center pb-16 md:pb-32 mb-6'> | |
| <h2 className='text-xl md:text-3xl font-bold'>🔥 인기 체험</h2> | |
| <div className='flex gap-2'> | |
| <button | |
| onClick={() => scrollByCard('left')} | |
| className='text-2xl px-3 focus:outline-none focus:ring-2 focus:ring-blue-500 rounded' | |
| aria-label='이전 체험 보기' | |
| > | |
| <IconArrowLeft size={32} /> | |
| </button> | |
| <button | |
| onClick={() => scrollByCard('right')} | |
| className='text-2xl px-3 focus:outline-none focus:ring-2 focus:ring-blue-500 rounded' | |
| aria-label='다음 체험 보기' | |
| > | |
| <IconArrowRight size={32} /> | |
| </button> | |
| </div> | |
| </div> | |
| {/* …the rest of the section… */} | |
| </section> | |
| ); |
🤖 Prompt for AI Agents
In src/app/(with-header)/components/PopularExperiences.tsx around lines 31 to
40, the arrow icons used for scrolling are clickable but lack accessibility
support. To fix this, wrap the IconArrowLeft and IconArrowRight components in
accessible button elements or add appropriate role="button" and tabindex="0"
attributes, and include keyboard event handlers to support keyboard navigation.
Also, add descriptive aria-labels to these elements to clearly convey their
purpose to screen readers.
| {/* 가로 슬라이드 카드 리스트 */} | ||
| <div | ||
| ref={sliderRef} | ||
| className='flex gap-16 md:gap-32 lg:gap-24 overflow-x-auto scroll-smooth no-scrollbar' | ||
| > | ||
| {[...Array(4)].map((_, idx) => ( | ||
| // 카드 wrapper: flex-shrink-0으로 크기 고정 + 'card' 클래스로 식별 | ||
| <div key={idx} className='flex-shrink-0 card'> | ||
| <ExperienceCard /> | ||
| </div> | ||
| ))} | ||
| </div> | ||
| </section> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
🛠️ Refactor suggestion
키보드 네비게이션 지원을 추가하고 데이터 구조를 개선하세요.
현재 구현에서 개선이 필요한 부분들:
- 키보드 네비게이션 미지원
- 하드코딩된 4개 카드 배열
키보드 이벤트 핸들러 추가:
+ const handleKeyDown = (event: React.KeyboardEvent) => {
+ if (event.key === 'ArrowLeft') {
+ scrollByCard('left');
+ } else if (event.key === 'ArrowRight') {
+ scrollByCard('right');
+ }
+ };
<div
ref={sliderRef}
- className='flex gap-16 md:gap-32 lg:gap-24 overflow-x-auto scroll-smooth no-scrollbar'
+ className='flex gap-16 md:gap-32 lg:gap-24 overflow-x-auto scroll-smooth no-scrollbar'
+ tabIndex={0}
+ onKeyDown={handleKeyDown}
+ role='region'
+ aria-label='인기 체험 목록'
>하드코딩된 카드 배열을 props나 API 데이터로 대체하는 코드를 생성해드릴까요?
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {/* 가로 슬라이드 카드 리스트 */} | |
| <div | |
| ref={sliderRef} | |
| className='flex gap-16 md:gap-32 lg:gap-24 overflow-x-auto scroll-smooth no-scrollbar' | |
| > | |
| {[...Array(4)].map((_, idx) => ( | |
| // 카드 wrapper: flex-shrink-0으로 크기 고정 + 'card' 클래스로 식별 | |
| <div key={idx} className='flex-shrink-0 card'> | |
| <ExperienceCard /> | |
| </div> | |
| ))} | |
| </div> | |
| </section> | |
| // (inside your PopularExperiences component) | |
| const handleKeyDown = (event: React.KeyboardEvent) => { | |
| if (event.key === 'ArrowLeft') { | |
| scrollByCard('left'); | |
| } else if (event.key === 'ArrowRight') { | |
| scrollByCard('right'); | |
| } | |
| }; | |
| return ( | |
| <> | |
| {/* 가로 슬라이드 카드 리스트 */} | |
| <div | |
| ref={sliderRef} | |
| className='flex gap-16 md:gap-32 lg:gap-24 overflow-x-auto scroll-smooth no-scrollbar' | |
| tabIndex={0} | |
| onKeyDown={handleKeyDown} | |
| role='region' | |
| aria-label='인기 체험 목록' | |
| > | |
| {[...Array(4)].map((_, idx) => ( | |
| // 카드 wrapper: flex-shrink-0으로 크기 고정 + 'card' 클래스로 식별 | |
| <div key={idx} className='flex-shrink-0 card'> | |
| <ExperienceCard /> | |
| </div> | |
| ))} | |
| </div> | |
| </> | |
| ); |
🤖 Prompt for AI Agents
In src/app/(with-header)/components/PopularExperiences.tsx around lines 42 to
54, the current horizontal slider lacks keyboard navigation support and uses a
hardcoded array of 4 cards. To fix this, add keyboard event handlers to enable
arrow key navigation for accessibility, and replace the hardcoded array with
dynamic data passed via props or fetched from an API. This will improve
usability and make the component data-driven.
| {[...Array(4)].map((_, idx) => ( | ||
| // 카드 wrapper: flex-shrink-0으로 크기 고정 + 'card' 클래스로 식별 | ||
| <div key={idx} className='flex-shrink-0 card'> | ||
| <ExperienceCard /> | ||
| </div> | ||
| ))} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
카드 데이터를 동적으로 처리하도록 개선하세요.
현재 하드코딩된 4개 카드 배열은 확장성이 떨어집니다.
컴포넌트를 더 유연하게 만들기 위해 props를 사용하는 것을 고려해보세요:
+interface PopularExperiencesProps {
+ experiences?: ExperienceData[];
+ maxItems?: number;
+}
-export default function PopularExperiences() {
+export default function PopularExperiences({
+ experiences = [],
+ maxItems = 4
+}: PopularExperiencesProps) {
// ... existing code ...
- {[...Array(4)].map((_, idx) => (
+ {(experiences.length > 0 ? experiences : [...Array(maxItems)]).slice(0, maxItems).map((experience, idx) => (
<div key={idx} className='flex-shrink-0 card'>
- <ExperienceCard />
+ <ExperienceCard data={experience} />
</div>
))}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {[...Array(4)].map((_, idx) => ( | |
| // 카드 wrapper: flex-shrink-0으로 크기 고정 + 'card' 클래스로 식별 | |
| <div key={idx} className='flex-shrink-0 card'> | |
| <ExperienceCard /> | |
| </div> | |
| ))} | |
| // Add a props interface so this component can receive data and a limit | |
| interface PopularExperiencesProps { | |
| experiences?: ExperienceData[]; | |
| maxItems?: number; | |
| } | |
| export default function PopularExperiences({ | |
| experiences = [], | |
| maxItems = 4, | |
| }: PopularExperiencesProps) { | |
| // ... existing code ... | |
| {(experiences.length > 0 ? experiences : [...Array(maxItems)]) | |
| .slice(0, maxItems) | |
| .map((experience, idx) => ( | |
| // 카드 wrapper: flex-shrink-0으로 크기 고정 + 'card' 클래스로 식별 | |
| <div key={idx} className='flex-shrink-0 card'> | |
| <ExperienceCard data={experience} /> | |
| </div> | |
| ))} | |
| } |
🤖 Prompt for AI Agents
In src/app/(with-header)/components/PopularExperiences.tsx around lines 47 to
52, the code currently renders a fixed array of 4 cards, which limits
scalability. Modify the component to accept an array of card data as a prop and
map over this dynamic data to render ExperienceCard components accordingly. This
change will make the component more flexible and reusable with varying numbers
of cards.
| > | ||
| {[...Array(4)].map((_, idx) => ( | ||
| // 카드 wrapper: flex-shrink-0으로 크기 고정 + 'card' 클래스로 식별 | ||
| <div key={idx} className='flex-shrink-0 card'> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기서 클래스를 지정해준다음에 querySelector로 찾도록 하신거군요!
하나 배워갑니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제 코드가 도움이 되었다니 다행입니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ref를 사용하는 UI에 대해서는 아직 부족한데 덕분에 배워갑니다!
추후에 motion라이브러리까지 적용하면 될것같네요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
넵~! API 연동까지 다 되면 motion 라이브러리 도입해보려구요. 감사합니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
슬라이더 기능도 넣어주시고 고생 많으셨습니다!!
LeeCh0129
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
체험 섹션 UI 구현 고생 많으셨습니다! 주석이 명확하게 달려 있어 흐름 파악이 수월했습니다 👍
📌 변경 사항 개요
📝 상세 내용
🔗 관련 이슈
🖼️ 스크린샷(선택사항)
globalnomad-popularexpriences.mp4
💡 참고 사항
Summary by CodeRabbit
신규 기능
스타일