Skip to content

Fix(#276): Viewer 패널 UI 개선#277

Open
stringnine wants to merge 8 commits into
devfrom
fix/276-viewer-fix
Open

Fix(#276): Viewer 패널 UI 개선#277
stringnine wants to merge 8 commits into
devfrom
fix/276-viewer-fix

Conversation

@stringnine
Copy link
Copy Markdown
Collaborator

@stringnine stringnine commented May 20, 2026

📌 관련 이슈

🏷️ PR 타입

  • ✨ 기능 추가 (Feature)
  • 🐛 버그 수정 (Bug Fix)
  • ♻️ 리팩토링 (Refactoring)
  • 🗑️ 코드 제거 (Chore)
  • 📝 문서 수정 (Documentation)
  • 🎨 스타일 변경 (Style)
  • ✅ 테스트 추가 (Test)

📝 작업 내용

  • 빈 상태 UI를 홈 화면과 동일한 ViewerUploadCard 컴포넌트로 교체 (중앙 정렬)
  • 드래그 앤 드롭 범위를 Viewer 전체 패널 → 카드 영역으로 한정
  • 파일 제목 상단 중앙 정렬 및 Figma 폰트 스펙 적용 (Pretendard 18px / 600 / leading-7)
  • PDF 페이지 이동 버튼을 텍스트(<, >) → SVG 아이콘으로 교체, hover 영역 및 색상 통일
  • PDF/이미지 패널 축소 시 콘텐츠도 함께 줄어들도록 반응형 처리
  • Ctrl+휠(데스크탑) / 핀치(모바일) 확대·축소 기능 추가, 줌 시 스크롤 가능
  • 줌 인터랙션 DOM 직접 업데이트로 즉각 반응, 배율 방식(15%)으로 자연스러운 줌감
  • PDF 렌더링 품질 개선 (HiDPI 대응, 픽셀 예산 캡 적용)
  • ResizeObserver rAF 배칭으로 리사이즈 버벅임 최소화

📸 스크린샷 (UI 변경 시 필수)

screen-capture.mp4

✅ 체크리스트

공통

  • 셀프 리뷰를 완료했습니다
  • 코드 리뷰를 받을 준비가 완료되었습니다
  • pnpm tsc --noEmit 타입 체크를 통과했습니다
  • 브랜치명 컨벤션을 준수했습니다 (type/이슈번호-작업명)

UI/레이아웃 변경 시

  • 태블릿(768px~) / 데스크탑(1280px~) / 와이드(1360px~) 반응형을 확인했습니다
  • PageContainer / ContentGrid 공통 컴포넌트를 활용했습니다

📎 기타 참고사항

  • Ctrl+휠 줌 시 브라우저 기본 확대 동작은 e.preventDefault()로 차단
  • PDF 렌더링은 PDF_RENDER_QUALITY_SCALE = 2.5 기준, MAX_PDF_RENDER_PIXELS = 8_000_000 픽셀 예산 내에서 동적 조정
  • useNotes.ts 무한 스크롤 쿼리 키 분리 및 client.ts BASE_URL 폴백 처리 포함

Summary by CodeRabbit

릴리스 노트

  • New Features

    • 파일 뷰어에서 PDF/이미지의 줌 및 핀치 확대 기능 추가
    • 동적 스케일링으로 화면에 최적화된 파일 렌더링 지원
    • 파일 업로드 UI 개선 및 드래그드롭 기능 강화
    • 노트 목록 무한 스크롤 지원 추가
  • Style

    • 업로드 버튼 애니메이션 속도 개선
  • Chores

    • API 연결 안정성 강화

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Caution

Review failed

An error occurred during the review process. Please try again later.

📝 Walkthrough

Walkthrough

FileRenderer가 컨테이너 폭 기반 동적 스케일과 줌/핀치 확대 기능을 갖춘 PDF/이미지 렌더링으로 개선되고, ViewerContent의 빈 상태 UI가 ViewerUploadCard로 교체되며 드래그/드롭이 카드 영역으로 한정됩니다. 추가로 노트 목록 쿼리 키를 분리하고 API 클라이언트 기본 URL 설정을 보완했습니다.

Changes

Viewer 패널 UI 및 파일 렌더링

Layer / File(s) Summary
FileRenderer 반응형 스케일 및 줌 기능
src/features/chat/components/leftpanel/FileRenderer.tsx
PDF/이미지 렌더링에 getClientReachableUrl 유틸을 도입하여 로컬/원격 환경별 URL을 조정. ResizeObserver로 컨테이너 폭을 감지해 fit 스케일, devicePixelRatio, 품질 스케일을 조합한 동적 캔버스 크기 산정. Ctrl+휠 및 핀치 줌 이벤트를 스크롤 컨테이너에 연결하고 로드 시 줌 상태를 초기화.
ViewerContent 빈 상태 및 드래그/드롭 개선
src/features/chat/components/leftpanel/ViewerContent.tsx, src/pages/components/ViewerUploadCard.tsx
ViewerEmpty 대신 ViewerUploadCard를 빈 상태 UI로 사용하고, 드래그/드롭 이벤트를 최상위 컨테이너에서 카드 영역으로 위임. DragDropOverlay 제거 및 업로드 핸들러를 카드에 직접 전달. 버튼 애니메이션 지속 시간을 500ms로 단축.

쿼리 관리 및 API 설정

Layer / File(s) Summary
노트 목록 쿼리 키 분리
src/features/notes/hooks/useNotes.ts
noteKeys.list() 함수에 "paginated" 세그먼트를 추가하고, 무한 스크롤용 infiniteList() 함수를 신규 생성. useInfiniteNoteList의 queryKey를 noteKeys.infiniteList()로 변경해 페이지네이션과 무한 로드 캐시를 분리 관리.
API 클라이언트 기본 URL 설정
src/shared/api/client.ts
BASE_URL이 환경 변수 VITE_API_BASE_URL 값이 없을 때 undefined 대신 빈 문자열("")로 폴백되도록 변경.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Team-Proovy/Proovy-front#166: ViewerContent, ViewerUploadCard의 드래그앤드롭 업로드 흐름(isDragging, dragProps 전달)을 동일하게 수정하고 있습니다.
  • Team-Proovy/Proovy-front#139: FileRenderer.tsx를 도입한 PR이며, 본 PR이 PDF 로드 URL 처리 및 fit/줌/캔버스 스케일링을 추가로 수정하고 있습니다.
  • Team-Proovy/Proovy-front#220: FileRenderer의 드래그 이벤트 처리와 useFileUpload의 파일 타입 검증을 함께 다루고 있습니다.

Suggested labels

fix, enhancement

Suggested reviewers

  • dev-ldy03
  • Mingyeong-Kang

Poem

🐰 줌과 스케일로 파일이 춤을 추고,
드래그는 카드로 모여 반갑게,
쿼리 키는 분리되어 정렬되고,
빈 화면은 이제 그림으로 가득 차네!
반응형 viewer, 사용자 경험 한 단계 높았어요! ✨

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/276-viewer-fix

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@stringnine stringnine changed the title [Fix] Viewer 패널 UI 개선 Fix(#276): Viewer 패널 UI 개선 May 20, 2026
@stringnine stringnine self-assigned this May 20, 2026
@stringnine stringnine added bug 버그 발생 fix 코드 및 버그 수정 refactor 코드 및 구조 리팩토링 labels May 20, 2026
@stringnine
Copy link
Copy Markdown
Collaborator Author

@coderabbitai 코드 리뷰해줘

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read all changed files for review
echo "=== FileRenderer.tsx ==="
cat src/features/chat/components/leftpanel/FileRenderer.tsx

echo ""
echo "=== ViewerContent.tsx ==="
cat src/features/chat/components/leftpanel/ViewerContent.tsx

echo ""
echo "=== useNotes.ts ==="
cat src/features/notes/hooks/useNotes.ts

echo ""
echo "=== ViewerUploadCard.tsx ==="
cat src/pages/components/ViewerUploadCard.tsx

echo ""
echo "=== client.ts ==="
cat src/shared/api/client.ts

Length of output: 35258


@stringnine PR #277 코드 리뷰입니다. 전반적으로 HiDPI 지원, 줌 인터랙션, 반응형 레이아웃이 잘 구현되었습니다. 아래 몇 가지 개선 포인트를 공유드립니다.


🔴 버그

1. ViewerContent.tsx<input type="file"> 중복 마운트

fileInputRef가 두 개의 DOM 요소에 동시에 연결됩니다.

ViewerContent.tsx 반환부
└── <input type="file" ref={fileInputRef} .../>   ← 첫 번째 (orphan)
└── renderContent()
    └── ViewerUploadCard
        └── <input type="file" ref={fileInputRef} .../>  ← 두 번째 (ref가 여기로 덮어씌워짐)

React는 마지막으로 마운트된 요소에 ref를 할당하므로 ViewerContent<input>은 ref가 가리키지 않는 불필요한 DOM 노드가 됩니다. ViewerContent의 최상위 <input type="file"> 을 제거해 주세요.

// ViewerContent.tsx — 이 부분을 제거
return (
  <div className="relative h-full w-full">
-   <input
-     type="file"
-     ref={fileInputRef}
-     className="hidden"
-     onChange={handleFileChange}
-     accept={FILE_ACCEPT}
-   />
    {renderContent()}
  </div>
);

2. FileRenderer.tsx — 이미지 에러 상태가 새 파일 로드 시 초기화되지 않음

이미지 A 로드 실패 → 이미지 B로 전환 시, error 상태가 남아 있어 B가 정상 URL이어도 에러 UI가 표시됩니다. reachableFileUrl 변경 시 에러를 초기화하는 useEffect가 필요합니다.

useEffect(() => {
  setError(null);
}, [reachableFileUrl]);

🟡 성능 / 동작

3. FileRenderer.tsxnumPages가 PDF 렌더 useEffect 의존성 배열에 불필요하게 포함

// numPages는 effect 내부에서 참조되지 않아 불필요한 재렌더링을 유발합니다
}, [pageNumber, fileType, numPages, containerWidth, contentWidth]);
//                         ^^^^^^^^ 사용되지 않음

numPages를 제거하면 PDF 로드 직후 불필요한 페이지 재렌더링을 방지할 수 있습니다.

4. FileRenderer.tsxstyle.zoom 비표준 CSS 속성

// TypeScript도 CSSStyleDeclaration에 포함하지 않아 타입 캐스팅이 필요한 상태
(zoomWrapperRef.current.style as CSSStyleDeclaration & { zoom: string }).zoom = String(clamped);

zoom은 CSS 표준 사양에 포함되지 않습니다(Firefox는 v126에서야 지원 추가). 브라우저 호환성 및 타입 안정성을 위해 표준 transform: scale() 사용을 고려해 주세요.

// 권장 대안
if (zoomWrapperRef.current) {
  zoomWrapperRef.current.style.transform = `scale(${clamped})`;
  zoomWrapperRef.current.style.transformOrigin = 'top center';
}

단, transform: scale()은 레이아웃 공간을 점유하지 않으므로 스크롤 컨테이너 크기 계산을 함께 조정해야 합니다.


🟢 마이너 / 스타일

5. ViewerUploadCard.tsx — 버튼과 텍스트의 transition duration 불일치

// 버튼: duration-500
className="... transition-colors duration-500 hover:bg-[`#2A6AFF33`] ..."

// 내부 <p>: duration-700 (여전히 700ms)
className="... transition-colors duration-700 group-hover:text-[`#2542F0`]"

같은 hover 인터랙션에서 배경색(500ms)과 텍스트 색(700ms)이 서로 다른 속도로 변하면 어색하게 느껴질 수 있습니다. 동일한 duration으로 맞추는 것을 권장합니다.

6. FileRenderer.tsx — 불필요한 non-null assertion

// onTouchMove 내부
if (e.touches.length !== 2 || lastTouchDistRef.current === null) return;
// 위에서 null guard를 통과했으므로 ! 불필요
applyZoom(zoomRef.current * (dist / lastTouchDistRef.current!));
//                                                            ^

7. 에러 시 window.location.reload() UX

ViewerContentFileRenderer 양쪽 모두 "다시 시도" 버튼이 window.location.reload()를 호출합니다. 전체 페이지 리로드 대신 해당 파일만 재요청하는 방식이 사용자 경험에 더 적합합니다.


ℹ️ 참고

useNotes.tsnoteKeys.list 구조 변경

list 키가 [..., params][..., "paginated", params]로 변경되었습니다. invalidateQueries({ queryKey: noteKeys.lists() })는 상위 키를 사용하므로 정상 동작하지만, queryClient.getQueryData(noteKeys.list(...))처럼 직접 키를 사용하는 코드가 있다면 업데이트가 필요합니다.

Copy link
Copy Markdown
Collaborator

@L0521 L0521 left a comment

Choose a reason for hiding this comment

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

UI 개선 확인했습니다~~

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

Labels

bug 버그 발생 fix 코드 및 버그 수정 refactor 코드 및 구조 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Fix] Viewer 패널 UI 개선

2 participants