-
Notifications
You must be signed in to change notification settings - Fork 1
[Feat/#96] 노트 검색창 구현 #114
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
[Feat/#96] 노트 검색창 구현 #114
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Walkthrough최근 마크된 노트 항목을 클릭하면 노트 에디터로 이동하도록 네비게이션을 추가했고, 검색 노트 컴포넌트에 포탈 기반 드롭다운 검색 결과 표시, 하이라이트 렌더링, 키보드 및 포커스/클릭 외부 처리 등을 구현했습니다. (약 50단어 이내) Changes
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: 드롭다운 닫기
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
|
✨ Storybook 확인: 🔗 https://6785fc0fb0ff9f8d21d80624-tgiqxtbrmq.chromatic.com/ |
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: 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
📒 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경로의 파라미터를folderId와noteId로 정확하게 대체하고 있습니다.String()변환도 적절합니다.
24-27: 클릭 가능한 카드 구현이 적절합니다.카드 전체를 클릭 가능하게 만들어 UX를 개선했습니다.
cursor-pointer와hover: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 처리가 적절합니다.
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: 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를 추가하여 포털된 드롭다운 클릭 시 의도치 않게 닫히는 문제가 해결되었습니다.containerRef와dropdownRef모두 외부 클릭인 경우에만 드롭다운이 닫힙니다.
🧹 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
📒 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를 제공합니다. 외부에서 검색 결과 선택에 반응할 수 있어 유연한 통합이 가능합니다.
Summary
노트 검색창 구현
Tasks
Screenshot
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.