Files
shoptime/com.twin.app.shoptime/.docs/player-panel/TabContainerV2-Divider-Problem-Analysis.md
optrader fe9781ff1c [251111] docs: views - ShopNowContents.jsx, TabContainerV2-Divider-Pro...
🕐 커밋 시간: 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

🔧 주요 변경 내용:
  • 개발 문서 및 가이드 개선
2025-11-11 19:49:44 +09:00

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 분리 방식을 추천합니다.

이유

  1. 근본적인 해결: TVirtualGridList 구조적 한계를 완전히 회피
  2. 레이아웃 안정성: 각 컴포넌트가 독립적으로 동작하여 예측 가능한 결과
  3. 유지보수성: 기존 로직을 최소한만 수정하며 명확한 분리
  4. 사용자 경험: 포커스 이동이 더 명확하고 직관적

구현 우선순위

  1. ShopNow TVirtualGridList 분리
  2. YouMayLike TVirtualGridList 분리
  3. 구분선 SpottableDiv 추가
  4. 포커스 이동 핸들러 구현
  5. 테스트 및 디버깅

영향 범위

  • 수정 필요 파일: ShopNowContents.jsx 1개
  • 기존 기능: 모두 유지 가능
  • 성능 영향: 미미 (VirtualGridList 인스턴스 1개 추가)
  • 사용자 영향: 없음 (개선된 경험 제공)

관련 파일

  • src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx
  • src/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.jsx
  • src/views/PlayerPanel/PlayerTabContents/TabContents/YouMayLikeContents.jsx
  • src/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.v2.module.less
  • src/components/TVirtualGridList/TVirtualGridList.jsx