Skip to content

Conversation

@hyesngy
Copy link
Member

@hyesngy hyesngy commented Dec 6, 2025

Summary

관련 있는 Issue를 태그해주세요. (e.g. > - #100)

Tasks

  • 홈 최근 즐겨찾기한 노트 클릭 핸들러 추가
  • 노트 검색창 구현

Screenshot

image

Summary by CodeRabbit

  • New Features
    • 최근 마크된 항목을 클릭해 노트 편집기로 바로 이동 가능하도록 개선
    • 노트 편집기 검색을 드롭다운 결과로 표시하고 최대 결과 목록과 키보드 탐색(Enter/Escape), 포커스·클릭 아웃 동작 지원
    • 검색 결과에서 일치 텍스트를 강조 표시하고 결과 선택 시 에디터 내 위치로 바로 이동하도록 개선

✏️ Tip: You can customize this high-level summary in your review settings.

@hyesngy hyesngy self-assigned this Dec 6, 2025
@hyesngy hyesngy requested a review from a team as a code owner December 6, 2025 08:09
@hyesngy hyesngy added the ✨ Feature 기능 개발 label Dec 6, 2025
@hyesngy hyesngy linked an issue Dec 6, 2025 that may be closed by this pull request
@vercel
Copy link

vercel bot commented Dec 6, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
cardify Ready Ready Preview Comment Dec 6, 2025 8:21am

@coderabbitai
Copy link

coderabbitai bot commented Dec 6, 2025

Walkthrough

최근 마크된 노트 항목을 클릭하면 노트 에디터로 이동하도록 네비게이션을 추가했고, 검색 노트 컴포넌트에 포탈 기반 드롭다운 검색 결과 표시, 하이라이트 렌더링, 키보드 및 포커스/클릭 외부 처리 등을 구현했습니다. (약 50단어 이내)

Changes

Cohort / File(s) Summary
RecentMarkedNoteItem 네비게이션
src/pages/home/components/RecentMarkedNote/RecentMarkedNoteItem.tsx
컴포넌트 props에 noteId, folderId 추가. useNavigatePATHS.NOTE_EDITOR를 사용해 전체 아이템을 클릭 가능한 컨테이너로 만들고 handleClick으로 에디터로 이동하도록 연결.
검색 노트 스타일링
src/pages/note-editor/components/tiptap-ui/search-note/search-note.scss
컨테이너 레이아웃을 수직/상단 정렬로 변경. 드롭다운 블록 .search-results-dropdown, 항목 .search-result-item, 텍스트 .search-result-text, 하이라이트 .search-result-highlight 등 드롭다운 관련 클래스 추가 및 다크 모드 스타일 확장.
검색 노트 기능 확장
src/pages/note-editor/components/tiptap-ui/search-note/search-note.tsx
SearchResult 인터페이스 및 SearchNoteProps.onResultClick? 추가. 입력 기반 클라이언트 검색(매치 인덱스/컨텍스트 포함), 하이라이트 렌더러, 포탈로 최대 7개 결과 드롭다운 렌더링, 드롭다운 위치 관리, 클릭 외부 닫기, 키보드(Enter/Escape) 및 포커스 처리, 결과 선택 시 에디터 선택 위치 설정 및 onResultClick 호출 구현.

Sequence Diagram(s)

sequenceDiagram
    participant User as 사용자
    participant Input as SearchNote Input
    participant Component as SearchNote 컴포넌트
    participant Portal as ReactDOM Portal (드롭다운)
    participant Editor as TipTap 에디터

    User->>Input: 텍스트 입력 / 포커스
    Input->>Component: onChange / onFocus
    Component->>Component: findAllMatches 생성 (SearchResult 배열)
    Component->>Portal: 드롭다운 렌더(최대 7개)
    Portal->>User: 결과 표시(하이라이트)
    User->>Portal: 결과 클릭 또는 키보드 Enter
    Portal->>Component: 선택된 SearchResult 전달
    Component->>Editor: 에디터 선택 위치 설정 (from/to)
    Component->>Component: onResultClick 호출(if provided)
    User->>Portal: 클릭 외부 또는 Escape
    Portal->>Component: 드롭다운 닫기
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

  • 집중 검토 필요 영역:
    • search-note.tsx의 매치 탐색 알고리즘 및 findAllMatches 경계/성능 처리
    • 드롭다운 포지셔닝(리사이즈/스크롤 환경)과 포탈 렌더링의 z-index/스타일 충돌 가능성
    • 클릭-외부 감지, 포커스 흐름, 키보드 이벤트의 접근성 및 부작용
    • RecentMarkedNoteItem의 props 변화로 인한 호출부(상위 컴포넌트) 호환성 검사

Poem

🐰 클릭하면 에디터로 달려가네,
검색은 포탈로 빛나고, 하이라이트 춤추네.
키 하나로 선택하고, Escape로 숨고,
토끼가 기뻐 뛰네 — 코드에 당도한 햇살! ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 검색창 구현이라는 주요 변경사항을 명확하게 설명하고 있으며, 이슈 #96과도 연결되어 있습니다.
Description check ✅ Passed PR 설명이 템플릿의 필수 섹션(Summary, Tasks)을 포함하고 있으며, 관련 이슈 #96이 태그되어 있고 스크린샷도 첨부되어 있습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#96

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.

@github-actions
Copy link

github-actions bot commented Dec 6, 2025

✨ Storybook 확인: 🔗 https://6785fc0fb0ff9f8d21d80624-tgiqxtbrmq.chromatic.com/

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/pages/note-editor/components/tiptap-ui/search-note/search-note.tsx (1)

210-210: 결과 개수 제한을 상수나 prop으로 분리하는 것을 고려해주세요.

매직 넘버 7을 상수로 추출하면 가독성과 유지보수성이 향상됩니다.

+const MAX_SEARCH_RESULTS = 7;
+
 export const SearchNote = React.forwardRef<HTMLInputElement, SearchNoteProps>(
-              {searchResults.slice(0, 7).map((result) => (
+              {searchResults.slice(0, MAX_SEARCH_RESULTS).map((result) => (
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 74eac70 and afb4bc5.

📒 Files selected for processing (3)
  • src/pages/home/components/RecentMarkedNote/RecentMarkedNoteItem.tsx (1 hunks)
  • src/pages/note-editor/components/tiptap-ui/search-note/search-note.scss (1 hunks)
  • src/pages/note-editor/components/tiptap-ui/search-note/search-note.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/pages/note-editor/components/tiptap-ui/search-note/search-note.tsx (1)
src/pages/note-editor/hooks/use-tiptap-editor.ts (1)
  • useTiptapEditor (7-10)
src/pages/home/components/RecentMarkedNote/RecentMarkedNoteItem.tsx (4)
src/types/note/note.ts (1)
  • NoteItemProps (1-15)
src/routes/paths.ts (1)
  • PATHS (1-13)
src/pages/home/components/RecentMarkedNote/RecentMarkedNoteList.tsx (1)
  • item (15-17)
src/pages/home/components/RecentMarkedNote/RecentMarkedNoteItem.stories.tsx (1)
  • args (31-31)
src/pages/note-editor/components/tiptap-ui/search-note/search-note.scss (1)
src/pages/note-editor/components/tiptap-templates/simple/theme-toggle.tsx (2)
  • ThemeToggle (12-42)
  • document (31-33)
🔇 Additional comments (6)
src/pages/home/components/RecentMarkedNote/RecentMarkedNoteItem.tsx (2)

19-21: 네비게이션 로직이 올바르게 구현되었습니다.

PATHS.NOTE_EDITOR 경로의 파라미터를 folderIdnoteId로 정확하게 대체하고 있습니다. String() 변환도 적절합니다.


24-27: 클릭 가능한 카드 구현이 적절합니다.

카드 전체를 클릭 가능하게 만들어 UX를 개선했습니다. cursor-pointerhover:bg-brand-20 스타일도 적절하게 적용되었습니다.

src/pages/note-editor/components/tiptap-ui/search-note/search-note.scss (2)

1-50: 검색 컨테이너와 래퍼 스타일링이 잘 구현되었습니다.

다크 모드 지원과 함께 focus/hover 상태 전환이 적절하게 구현되어 있습니다.


104-120: Portal로 렌더링되는 드롭다운에 다크 모드가 적용되지 않을 수 있습니다.

.dark & 셀렉터는 부모 요소에 .dark 클래스가 있을 때 동작하지만, 드롭다운은 document.body로 포털되므로 .search-note 내부에 위치하지 않습니다. theme-toggle.tsx에서 .dark 클래스는 document.documentElement(html)에 토글됩니다.

다크 모드 셀렉터를 수정하여 포털된 요소에서도 동작하도록 해주세요:

 .search-results-dropdown {
   width: 240px;
   max-height: 336px;
   overflow-y: auto;
   background: #FFFFFF;
   border-radius: 4px;
   box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.04);
   outline: 1px solid #EEEEEE;
   outline-offset: -1px;
   z-index: 9999;

-  .dark & {
+  .dark & ,
+  :root.dark & {
     background: #191919;
     outline-color: #454545;
     box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.2);
   }
 }

또는 .search-result-item, .search-result-text, .search-result-highlight에도 동일하게 :root.dark 셀렉터를 추가해야 합니다.

Likely an incorrect or invalid review comment.

src/pages/note-editor/components/tiptap-ui/search-note/search-note.tsx (2)

53-95: 에디터 문서 순회 및 매칭 로직이 잘 구현되었습니다.

doc.descendants를 사용한 텍스트 노드 탐색과 컨텍스트 추출 로직이 적절합니다. useCallback 메모이제이션도 올바르게 적용되었습니다.


125-138: 키보드 핸들링이 잘 구현되었습니다.

Enter로 첫 번째 결과 선택, Escape로 검색 초기화 및 blur 처리가 적절합니다.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
src/pages/note-editor/components/tiptap-ui/search-note/search-note.tsx (2)

22-41: 이전 리뷰 이슈가 잘 수정되었습니다.

regex.test(part) 대신 part.toLowerCase() === query.toLowerCase()를 사용하여 global 플래그로 인한 lastIndex 문제가 해결되었습니다.


169-182: 이전 리뷰 이슈가 잘 수정되었습니다.

dropdownRef를 추가하여 포털된 드롭다운 클릭 시 의도치 않게 닫히는 문제가 해결되었습니다. containerRefdropdownRef 모두 외부 클릭인 경우에만 드롭다운이 닫힙니다.

🧹 Nitpick comments (2)
src/pages/note-editor/components/tiptap-ui/search-note/search-note.tsx (2)

126-139: 드롭다운 키보드 내비게이션 추가를 고려하세요.

현재 Enter 키는 첫 번째 결과만 선택합니다. 접근성 향상을 위해 화살표 키로 결과를 탐색하는 기능 추가를 고려해 보세요.

+  const [selectedIndex, setSelectedIndex] = React.useState(-1);
+
   const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
     if (e.key === "Enter") {
       e.preventDefault();
       if (searchResults.length > 0) {
-        handleResultClick(searchResults[0]);
+        const index = selectedIndex >= 0 ? selectedIndex : 0;
+        handleResultClick(searchResults[index]);
       }
     }
+    if (e.key === "ArrowDown" && isDropdownOpen) {
+      e.preventDefault();
+      setSelectedIndex((prev) => Math.min(prev + 1, Math.min(searchResults.length, 7) - 1));
+    }
+    if (e.key === "ArrowUp" && isDropdownOpen) {
+      e.preventDefault();
+      setSelectedIndex((prev) => Math.max(prev - 1, 0));
+    }
     if (e.key === "Escape") {
       setSearchQuery("");
       setSearchResults([]);
       setIsDropdownOpen(false);
+      setSelectedIndex(-1);
       (e.target as HTMLInputElement).blur();
     }
   };

204-225: 드롭다운 너비를 입력 필드와 동기화하는 것을 고려하세요.

현재 드롭다운 너비가 CSS에 의존합니다. 입력 필드 너비가 동적으로 변할 수 있다면, wrapperRef.current.getBoundingClientRect().width를 사용하여 인라인 스타일로 너비를 설정하면 더 일관된 UI를 제공할 수 있습니다.

   const updateDropdownPosition = React.useCallback(() => {
     if (wrapperRef.current) {
       const rect = wrapperRef.current.getBoundingClientRect();
       setDropdownPosition({
         top: rect.bottom + 4,
         left: rect.left,
+        width: rect.width,
       });
     }
   }, []);
             style={{
               position: "fixed",
               top: dropdownPosition.top,
               left: dropdownPosition.left,
+              width: dropdownPosition.width,
             }}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between afb4bc5 and 9d83aeb.

📒 Files selected for processing (1)
  • src/pages/note-editor/components/tiptap-ui/search-note/search-note.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/pages/note-editor/components/tiptap-ui/search-note/search-note.tsx (1)
src/pages/note-editor/hooks/use-tiptap-editor.ts (1)
  • useTiptapEditor (7-10)
🔇 Additional comments (3)
src/pages/note-editor/components/tiptap-ui/search-note/search-note.tsx (3)

54-96: LGTM!

doc.descendants를 사용한 문서 탐색과 위치 계산이 정확합니다. 컨텍스트 추출 시 경계 검사도 적절하게 처리되어 있습니다.


147-167: LGTM!

스크롤 및 리사이즈 이벤트 리스너 관리가 적절합니다. capture: true 옵션으로 모든 스크롤 컨테이너의 이벤트를 캐치하고, cleanup 함수에서 리스너를 정리합니다.


7-20: LGTM!

SearchResult 인터페이스와 onResultClick 콜백을 통해 확장 가능한 API를 제공합니다. 외부에서 검색 결과 선택에 반응할 수 있어 유연한 통합이 가능합니다.

@hyesngy hyesngy merged commit dc9a10b into develop Dec 6, 2025
7 checks passed
@hyesngy hyesngy deleted the feat/#96 branch December 6, 2025 14:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 기능 개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: 노트 검색창 구현

2 participants