🕐 커밋 시간: 2025. 11. 11. 19:49:42 📊 변경 통계: • 총 파일: 2개 • 추가: +2줄 • 삭제: -1줄 📁 추가된 파일: + com.twin.app.shoptime/.docs/player-panel/TabContainerV2-Divider-Problem-Analysis.md 📝 수정된 파일: ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.jsx 🔧 주요 변경 내용: • 개발 문서 및 가이드 개선
5.4 KiB
5.4 KiB
TabContainerV2 구분선 문제 분석 및 해결 방안
문제 개요
PlayerPanel의 TabContainerV2에서 ShopNowContents와 YouMayLikeContents 사이에 세로 구분선을 표시해야 하지만, 현재 TVirtualGridList 구조의 한계로 인해 올바르게 동작하지 않음
현재 구조 분석
1. TabContainerV2 구조
- 위치:
src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx - 3개의 tabIndex로 구성 (0: ShopNow, 1: LiveChannel, 2: ShopNowButton)
- version=2에서 ShopNow와 YouMayLike 통합 표시
2. ShopNowContents 구조
- 위치:
src/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.jsx - ShopNow 아이템 < 3개일 때 YouMayLike 아이템을 통합하여 표시
- combinedItems 배열로 ShopNow + YouMayLike 통합 관리
- TVirtualGridList로 가로 방향 렌더링 (itemWidth: 310px, itemHeight: 445px, spacing: 30px)
3. 현재 구분선 구현 로직
// YouMayLike 시작 지점 여부 (구분선 표시)
const isYouMayLikeStart = shopNowInfo && index === shopNowInfo.length;
return (
<>
{isYouMayLikeStart && <div className={css.youMayLikeDivider} />}
<TItemCard {...props} />
</>
);
문제 상세
1. TVirtualGridList 구조적 한계
- TVirtualGridList는 각 아이템이 고정된 크기를 가짐 (itemWidth: 310px)
- renderItem 함수 내에서 추가적인 요소(divider)를 렌더링하면 레이아웃 충돌 발생
- divider가 TItemCard와 같은 공간을 차지하려고 하여 빈 TItemCard가 표시되는 현상
2. 포커스 이동 문제
- divider가 포커스를 받거나 포커스 이동을 방해하는 현상
- 실제 상품과 포커스 위치가 불일치하는 문제
3. 간격 문제
- 구분선으로 인해 상품들 간의 간격이 넓어짐
- 사용자 경험 저하
해결 방안 분석
방안 1: TItemCard Wrapper 방식 ❌
구현:
<div className={css.itemWrapper}>
<TItemCard {...props} />
</div>
CSS:
.itemWrapper::before {
content: '';
width: 2px;
opacity: 0;
}
.itemWrapper.showDivider::before {
opacity: 1;
background: rgba(234, 234, 234, 0.3);
}
문제점:
- itemWidth를 310px → 327px로 증가시켜야 함
- 상품 간 간격이 넓어짐
- 포커스와 상품 위치 불일치
- 전체 레이아웃 변경 필요
방안 2: Divider 아이템 추가 방식 ❌
구현:
// combinedItems에 divider 추가
items.push({ _type: 'divider' });
// renderItem에서 처리
if (item._type === 'divider') {
return <div className={css.youMayLikeDivider} />;
}
문제점:
- divider가 TVirtualGridList 아이템으로 인식되어 TItemCard만큼 공간 차지
- ShopNow와 YouMayLike 사이 포커스 이동이 막힘
- 빈 공간이 생기는 문제 여전히 존재
방안 3: 두 개의 TVirtualGridList 분리 방식 ✅
구현:
<div className={css.shopNowContainer}>
<TVirtualGridList>
[ShopNow1][ShopNow2]
</TVirtualGridList>
</div>
<div className={css.dividerContainer}>
<div className={css.youMayLikeDivider} />
</div>
<div className={css.youMayLikeContainer}>
<TVirtualGridList>
[YouMayLike1][YouMayLike2]
</TVirtualGridList>
</div>
장점:
- 구분선을 완벽하게 제어 가능
- 각 TVirtualGridList가 독립적으로 동작
- 빈 TItemCard 문제 해결
- 레이아웃 깨짐 없음
- 기존 기능 모두 유지 가능
고려사항:
- 포커스 이동 핸들러 구현 필요
- ShopNow 마지막 아이템 → 구분선 → YouMayLike 첫 아이템
- YouMayLike 첫 아이템 → 구분선 → ShopNow 마지막 아이템
- Spotlight 컨테이너 간 이동 수동 처리 필요
포커스 이동 구현 예시:
// ShopNow 마지막 아이템
onSpotlightRight={() => Spotlight.focus('divider-element')}
// 구분선 SpottableDiv
<SpottableDiv
spotlightId="divider-element"
onSpotlightLeft={() => Spotlight.focus('shop-now-last')}
onSpotlightRight={() => Spotlight.focus('you-may-like-first')}
>
<div className={css.youMayLikeDivider} />
</SpottableDiv>
// YouMayLike 첫 아이템
onSpotlightLeft={() => Spotlight.focus('divider-element')}
추천 해결책
방안 3: 두 개의 TVirtualGridList 분리 방식을 추천합니다.
이유
- 근본적인 해결: TVirtualGridList 구조적 한계를 완전히 회피
- 레이아웃 안정성: 각 컴포넌트가 독립적으로 동작하여 예측 가능한 결과
- 유지보수성: 기존 로직을 최소한만 수정하며 명확한 분리
- 사용자 경험: 포커스 이동이 더 명확하고 직관적
구현 우선순위
- ShopNow TVirtualGridList 분리
- YouMayLike TVirtualGridList 분리
- 구분선 SpottableDiv 추가
- 포커스 이동 핸들러 구현
- 테스트 및 디버깅
영향 범위
- 수정 필요 파일:
ShopNowContents.jsx1개 - 기존 기능: 모두 유지 가능
- 성능 영향: 미미 (VirtualGridList 인스턴스 1개 추가)
- 사용자 영향: 없음 (개선된 경험 제공)
관련 파일
src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsxsrc/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.jsxsrc/views/PlayerPanel/PlayerTabContents/TabContents/YouMayLikeContents.jsxsrc/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.v2.module.lesssrc/components/TVirtualGridList/TVirtualGridList.jsx