Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughEmotion 기반의 인라인 styled 컴포넌트들을 각 컴포넌트별 Changes
Sequence Diagram(s)(생성 조건 미충족 — 변경 대부분이 스타일 추출 및 일부 props/로직 확장으로, 다중 컴포넌트 간 새로운 제어 흐름을 시각화할 필요 없음.) Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 분 Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing touches
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
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 |
There was a problem hiding this comment.
Actionable comments posted: 16
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
src/components/common/Modal/ReplyModal.tsx (1)
73-81: 삭제/신고 로직이 반대로 구현되어 있습니다.조건부 렌더링 로직에 심각한 오류가 있습니다:
isMyReply가true(내 댓글)일 때 "신고하기"가 표시됩니다.isMyReply가false(타인의 댓글)일 때 "삭제하기"가 표시되고handleDelete가 호출됩니다.이는 정반대의 동작입니다. 사용자는 자신의 댓글을 삭제할 수 있어야 하고, 타인의 댓글을 신고할 수 있어야 합니다.
🔎 수정 제안
<ModalContent> - {isMyReply ? ( - <OptionItem className="report"> - <div className="option-text">신고하기</div> - </OptionItem> - ) : ( + {isMyReply ? ( <OptionItem onClick={handleDelete} className="delete"> <div className="option-text">삭제하기</div> </OptionItem> + ) : ( + <OptionItem className="report"> + <div className="option-text">신고하기</div> + </OptionItem> )} </ModalContent>src/components/group/MyGroupCard.tsx (1)
30-36: handleClick 함수의 조건부 로직으로 인한 부작용 확인됨
hasDeadline조건에 따라onClick콜백이 무시되는 문제가 확인되었습니다. MyGroupCard는 MyGroupBox.tsx에서만 사용되며, 두 곳 모두에서onClick핸들러를 전달합니다:
- 첫 번째 사용 (162-166):
onClick={() => navigate(\detail/joined/${groups[0].id}`)}- deadline이 있으면/group/detail/{id}`로 네비게이션되어 의도한 경로와 다름- 두 번째 사용 (177-185):
onClick={() => handleCardClick(g.id)}- deadline이 있으면onClick이 호출되지 않음이 동작 변경은 deadline 있는/없는 그룹의 처리 방식을 근본적으로 달리하므로, 다음을 명확히 해야 합니다:
hasDeadline여부와 관계없이 동일하게 동작해야 하는지, 아니면 의도적으로 다르게 처리하려는 것인지- 부모 컴포넌트의
onClick핸들러 의존성을 재검토할 필요src/components/Mypage/MenuButton.tsx (1)
7-7: 사용하지 않는 prop을 제거하거나 구현을 완료하세요.
textColorprop이 인터페이스에 선언되어 있지만 컴포넌트 내에서 실제로 사용되지 않습니다. 이 prop을 사용할 계획이라면Wrapper나 내부 요소에 적용하고, 그렇지 않다면 인터페이스에서 제거하세요.🔎 textColor를 사용하지 않는 경우 제안하는 수정
export interface MenuButtonProps { src: string; name: string; - textColor?: string; isButton?: boolean; onClick?: () => void; }src/components/common/Modal/Snackbar.tsx (1)
25-25: Memory.tsx에서 onClose를 useCallback으로 메모이제이션하세요Memory.tsx의 Snackbar 사용처(328-332줄)에서
onClose={() => setShowSnackbar(false)}를 인라인 함수로 전달하고 있습니다. 매 렌더링마다 새로운 함수가 생성되므로 Snackbar의 useEffect 의존성 배열이 변경되어 타이머가 매번 리셋됩니다. 결과적으로 설정된 5초(variant="bottom") 또는 2초 타이머가 제대로 작동하지 않습니다.useCallback을 사용하여 메모이제이션하거나, PopupContainer를 통한 일관된 팝업 관리 방식으로 변경하세요.
🧹 Nitpick comments (43)
src/components/common/Post/PostBody.styled.ts (1)
11-43: 주석 처리된 코드를 제거해주세요.PostContent 스타일은 전반적으로 잘 구현되었으나, 다음 사항들을 개선하면 좋겠습니다:
- Line 26: 주석 처리된
word-wrap: break-word;코드- Lines 39-40: 주석 처리된 width/height 코드
주석 처리된 코드는 유지보수성을 저해하므로 제거하는 것을 권장합니다. 필요한 경우 Git 히스토리에서 확인할 수 있습니다.
🔎 주석 제거 제안
white-space: pre-wrap; // 개행문자 유지 - /* word-wrap: break-word; // 긴 텍스트 줄바꿈 */ display: -webkit-box;position: absolute; bottom: 0px; right: 0px; - /* width: 20px; - height: 20px; */ pointer-events: none; // 클릭 이벤트 방지src/components/search/GroupSearchResult.styled.ts (1)
80-84: 하드코딩된 색상 값을 테마 색상으로 교체하는 것을 고려해보세요.Line 81에서
#ff6b6b대신colors.red를 사용하면 디자인 시스템과의 일관성을 유지할 수 있습니다. 다만, 기존 색상과 약간의 차이가 있으므로 디자인 의도를 확인 후 적용하시면 됩니다.🔎 제안하는 수정사항
export const ErrorText = styled.p` - color: #ff6b6b; + color: ${colors.red}; font-size: ${typography.fontSize.sm}; text-align: center; `;src/components/search/RecentSearchTabs.styled.ts (1)
39-39: 파일 끝의 빈 줄파일 끝에 불필요한 빈 줄이 있습니다. 제거하는 것을 고려해보세요.
🔎 제안하는 수정
export const Text = styled.p` color: ${colors.grey[200]}; font-size: ${typography.fontSize.sm}; font-weight: ${typography.fontWeight.regular}; text-align: center; line-height: 24px; `; - -src/components/group/MyGroupModal.styled.ts (1)
48-55: 테마 색상을 사용하는 것이 좋습니다.ErrorMessage에서 하드코딩된 색상(
#ff6b6b) 대신 전역 테마의colors.red를 사용하면 일관성이 향상됩니다. 다른 styled 파일(예: PasswordModal.styled.ts)도 동일한 패턴을 따르고 있습니다.🔎 테마 색상 적용 제안
export const ErrorMessage = styled.div` display: flex; justify-content: center; align-items: center; padding: 40px 20px; - color: #ff6b6b; + color: ${colors.red}; font-size: ${typography.fontSize.base}; `;src/components/feed/TabBar.styled.ts (1)
48-57: 매직 넘버를 상수로 추출하는 것을 고려해보세요.Line 56의
80은 TabButton의 width(60px) + Container의 gap(20px)을 계산한 값입니다. 이러한 값들이 여러 곳에 분산되어 있으면, 나중에 스타일 변경 시 일관성을 유지하기 어려울 수 있습니다.🔎 상수 추출 제안
+const TAB_WIDTH = 60; +const TAB_GAP = 20; +const TAB_SPACING = TAB_WIDTH + TAB_GAP; + export const Container = styled.div` ... - gap: 20px; + gap: ${TAB_GAP}px; ... `; export const TabButton = styled.div` ... - width: 60px; + width: ${TAB_WIDTH}px; ... `; export const ActiveIndicator = styled.div<ActiveIndicatorProps>` ... - transform: translateX(${props => props.activeIndex * 80}px); + transform: translateX(${props => props.activeIndex * TAB_SPACING}px); `;src/components/common/Modal/ImageViewer.styled.ts (1)
10-10: 디자인 시스템 색상 상수 사용을 권장합니다.하드코딩된
rgba(18, 18, 18, 0.8)대신 글로벌 색상 상수를 사용하면 디자인 시스템과의 일관성을 유지할 수 있습니다. 다만 현재colors.black에는 0.8 투명도가 정의되어 있지 않으므로, 필요시 글로벌 스타일에 추가하거나 기존 투명도 값을 활용하는 것을 고려해보세요.src/components/common/Post/SubReply.styled.ts (1)
4-14: 코드 중복: DeletedContainer가 Reply.styled.ts와 동일합니다.
DeletedContainer가Reply.styled.ts에도 동일한 정의로 존재합니다. 향후 유지보수성을 위해 공통 스타일 모듈로 추출하는 것을 고려해볼 수 있습니다.src/components/common/Post/PostFooter.styled.ts (1)
11-13: 클릭 불가능한 이미지의 커서 스타일 개선을 고려해보세요.현재 모든
img요소에cursor: pointer가 적용되지만, PostFooter.tsx의 잠금 아이콘(line 96)처럼 클릭 이벤트가 없는 이미지도 포인터 커서를 표시합니다. 사용자 경험 개선을 위해 더 구체적인 선택자를 사용하는 것을 고려해보세요.🔎 개선 제안
- img { - cursor: pointer; - } + .left img { + cursor: pointer; + }또는 클릭 가능한 이미지에만 명시적으로 클래스를 추가하는 방법도 있습니다.
src/components/feed/FeedDetailPostBody.styled.ts (1)
10-43: hasImage prop이 스타일에 사용되지 않습니다.
PostContentProps인터페이스에서hasImageboolean을 정의했지만,PostContent스타일 정의 내에서 이 prop을 실제로 참조하지 않습니다. 향후 사용 예정이 아니라면 불필요한 prop 전달을 줄이기 위해 제거하는 것을 고려해보세요.🔎 제안하는 수정안
-export interface PostContentProps { - hasImage: boolean; -} - -export const PostContent = styled.div<PostContentProps>` +export const PostContent = styled.div` display: flex; flex-direction: column; gap: 16px;src/components/feed/FeedDetailPost.styled.ts (2)
7-8: 주석 처리된 코드 정리를 고려해보세요.min-width와 max-width 규칙이 주석 처리되어 있습니다. 다른 styled 파일들에서도 동일한 패턴이 보이는데, 향후 사용 예정이 아니라면 제거하거나, 사용 예정이라면 TODO 주석으로 의도를 명확히 하는 것이 좋겠습니다.
Also applies to: 17-18
15-23: width 값의 매직 넘버를 명확히 해주세요.
BorderBottom의width: 94.8%는 특이한 값입니다. 이 값이 특정 패딩 계산을 고려한 것이라면calc()함수를 사용하거나 주석으로 계산 근거를 설명하는 것이 유지보수에 도움이 됩니다.예시:
width: calc(100% - 40px); /* 좌우 padding 20px씩 제외 */src/components/search/SearchBar.styled.ts (1)
6-10: 중복된 width 선언을 정리하세요.Line 6에서
width: 100%로 설정한 후, Line 10에서width: calc(100% - 40px)로 다시 설정하고 있습니다. 첫 번째 선언은 불필요하므로 제거하는 것이 좋습니다.🔎 제안하는 수정
display: flex; align-items: center; - width: 100%; height: 40px; background-color: var(--color-darkgrey-main); border-radius: 12px; width: calc(100% - 40px);src/components/common/TitleHeader.tsx (1)
24-30: 인라인 스타일을 styled 컴포넌트로 이동하는 것을 권장합니다.스타일을 분리하는 이번 리팩토링의 취지와 맞지 않게 24번, 29번 라인에서 인라인 스타일을 사용하고 있습니다. cursor 로직을 prop을 받는 styled 컴포넌트로 추출하면 일관성을 유지할 수 있습니다.
🔎 제안하는 수정 방안
TitleHeader.styled.ts에 새로운 styled 컴포넌트 추가:
export const IconWrapper = styled.div<{ clickable?: boolean }>` cursor: ${({ clickable }) => (clickable ? 'pointer' : 'default')}; `;TitleHeader.tsx에서 사용:
- <div onClick={onLeftClick} style={{ cursor: onLeftClick ? 'pointer' : 'default' }}> + <IconWrapper onClick={onLeftClick} clickable={!!onLeftClick}> {leftIcon} - </div> + </IconWrapper> <div className="title">{title}</div> {rightIcon ? ( - <div onClick={onRightClick} style={{ cursor: onRightClick ? 'pointer' : 'default' }}> + <IconWrapper onClick={onRightClick} clickable={!!onRightClick}> {rightIcon} - </div> + </IconWrapper>src/components/common/TitleHeader.styled.ts (2)
13-13: CSS 변수 사용으로 일관성을 맞추세요.13번 라인에서
colors.black.main을 직접 사용하고 있지만, 다른 곳(23-24번 라인)에서는 CSS 변수(var(--color-*))를 사용하고 있습니다. 일관성을 위해 CSS 변수를 사용하는 것을 권장합니다.🔎 제안하는 수정
- background-color: ${colors.black.main}; + background-color: var(--color-black-main);
4-14: MainHeader와의 코드 중복을 검토하세요.HeaderWrapper가 MainHeader.styled.ts의 HeaderWrapper와 거의 동일한 구조입니다. 공통 styled 컴포넌트로 추출하여 재사용하는 것을 고려해보세요.
Related code:
src/components/common/MainHeader.styled.ts(lines 2-14)에 동일한 구조의 HeaderWrapper가 있습니다.src/components/common/Modal/MoreMenu.styled.ts (3)
17-17: 정의된 색상 상수를 사용하세요.하드코딩된 색상값 대신
colors.black[10]을 사용하는 것이 일관성 있습니다. global.ts에 동일한 값이 정의되어 있습니다.🔎 제안하는 수정
- background-color: rgba(18, 18, 18, 0.1); + background-color: ${colors.black[10]};
52-58: 중복된 return 문을 제거하세요.모든 variant 케이스가 명시적으로 처리되므로 57번 라인의 return 문은 도달할 수 없는 코드입니다.
🔎 제안하는 수정
color: ${({ variant }) => { if (variant === 'edit') return colors.white; if (variant === 'delete') return colors.red; if (variant === 'report') return colors.red; - if (variant === 'pin') return colors.white; - return colors.white; + return colors.white; // 'pin' }};
48-103: 'pin' variant을 제거하고 중복 스타일링을 정리하세요.'pin' variant가 코드베이스 어디서도 사용되지 않습니다. MoreMenu.tsx에서는 'edit', 'delete', 'report' variant만 사용되며, 'pin' variant의 스타일링(padding 및 border 규칙)도 default 케이스와 완전히 동일합니다. 색상 로직도 'pin'은 colors.white를 반환하며 이는 default 반환값과 같습니다.
제안하는 수정
-export const Button = styled.div<{ variant: 'edit' | 'delete' | 'report' | 'pin' }>` +export const Button = styled.div<{ variant: 'edit' | 'delete' | 'report' }>` display: flex; height: 50px; align-items: center; color: ${({ variant }) => { if (variant === 'edit') return colors.white; if (variant === 'delete') return colors.red; if (variant === 'report') return colors.red; - if (variant === 'pin') return colors.white; return colors.white; }}; font-size: ${typography.fontSize.base}; font-weight: ${typography.fontWeight.semibold}; line-height: 24px; border-bottom: 1px solid ${colors.grey[400]}; cursor: pointer; - ${({ variant }) => { - if (variant === 'report') { - return ` - padding: 0; - border-bottom: none; - `; - } - if (variant === 'pin') { - return ` - &:first-of-type { - padding: 13px 12px 21px 12px; - } - - &:nth-of-type(2) { - padding: 13px 12px 21px 12px; - } - - &:last-of-type { - padding: 21px 12px 13px 12px; - border-bottom: none; - } - `; - } - return ` + ${({ variant }) => + variant === 'report' + ? ` + padding: 0; + border-bottom: none; + ` + : ` &:first-of-type { padding: 13px 12px 21px 12px; } &:nth-of-type(2) { padding: 13px 12px 21px 12px; } &:last-of-type { padding: 21px 12px 13px 12px; border-bottom: none; } - `; - }} + `} `;src/components/feed/TotalBar.styled.ts (1)
5-6: 주석 처리된 코드를 고려해보세요.min-width와 max-width 규칙이 주석 처리되어 있습니다. 다른 컴포넌트 스타일 파일에서도 유사한 패턴이 보이는데, 이러한 주석 처리된 코드는 향후 혼란을 야기할 수 있습니다. 필요하지 않다면 제거하고, 나중에 사용할 계획이라면 TODO 주석으로 설명을 추가하는 것을 권장합니다.
🔎 제안: 주석 제거 또는 설명 추가
옵션 1: 주석 제거
export const Container = styled.div` width: 100%; - /* min-width: 320px; - max-width: 540px; */ padding: 0 20px; margin: 0 auto; `;옵션 2: TODO로 의도 명확히 하기
export const Container = styled.div` width: 100%; + /* TODO: 반응형 디자인 적용 시 활성화 예정 /* min-width: 320px; max-width: 540px; */ padding: 0 20px; margin: 0 auto; `;src/components/group/GroupCard.styled.ts (2)
4-22: 선택적 개선: 스타일 속성 순서 조정
border-top(9-14행)과border(15행)가 함께 정의되어 있습니다. 로직상 문제는 없지만, 관련 속성들을 그룹화하면 가독성이 향상됩니다.🔎 개선 제안
export const Card = styled.div<{ cardType: 'main' | 'search' | 'modal'; isFirstCard?: boolean }>` display: flex; align-items: center; background: ${({ cardType }) => cardType === 'search' ? colors.black.main : colors.darkgrey.main}; + border: ${({ cardType }) => (cardType === 'main' ? `1px solid ${colors.grey[300]}` : '')}; border-top: ${({ cardType, isFirstCard }) => cardType === 'search' && isFirstCard ? 'none' : cardType === 'search' ? `1px solid ${colors.darkgrey.dark}` : 'none'}; - border: ${({ cardType }) => (cardType === 'main' ? `1px solid ${colors.grey[300]}` : '')}; border-radius: ${({ cardType }) => (cardType === 'search' ? `none` : '12px')}; box-sizing: border-box; padding: ${({ cardType }) => (cardType === 'search' ? '24px 12px' : '12px')}; gap: 12px; min-width: 232px; cursor: pointer; `;
87-115: 선택적 개선: 사용하지 않는 props 제거
Participant,RecruitingDeadline,OngoingDeadline컴포넌트에isRecommendprop이 정의되어 있지만 실제로는 사용되지 않습니다. 향후 사용 계획이 없다면 제거하는 것이 타입 정의를 간결하게 유지하는 데 도움이 됩니다.🔎 개선 제안
-export const Participant = styled.div<{ isRecommend: boolean }>` +export const Participant = styled.div` display: flex; align-items: center; gap: 4px; color: ${colors.white}; font-size: ${typography.fontSize.xs}; font-weight: ${typography.fontWeight.medium}; img { width: 16px; height: 16px; } `; export const MaximumParticipants = styled.div` color: ${colors.grey[100]}; font-size: ${typography.fontSize.xs}; `; -export const RecruitingDeadline = styled.div<{ isRecommend: boolean }>` +export const RecruitingDeadline = styled.div` font-size: ${typography.fontSize.xs}; font-weight: ${typography.fontWeight.medium}; color: ${colors.white}; `; -export const OngoingDeadline = styled.div<{ isRecommend: boolean }>` +export const OngoingDeadline = styled.div` font-size: ${typography.fontSize.xs}; font-weight: ${typography.fontWeight.medium}; color: ${colors.red}; `;src/components/common/Wrapper.styled.ts (1)
1-14: 글로벌 색상 시스템을 사용하세요.Line 13에서 하드코딩된 색상 값
#121212를 사용하고 있습니다. 같은 PR의MenuButton.styled.ts처럼 글로벌 스타일에서 색상을 임포트하여 일관성과 유지보수성을 높이는 것이 좋습니다.🔎 제안하는 수정 사항
import styled from '@emotion/styled'; +import { colors } from '@/styles/global/global'; export const Wrapper = styled.div` display: flex; position: relative; flex-direction: column; align-items: center; justify-content: center; min-width: 320px; max-width: 767px; height: 100vh; margin: 0 auto; - background-color: #121212; + background-color: ${colors.black.main}; `;src/components/feed/OtherFeed.styled.ts (1)
11-23: LGTM! EmptyState 컴포넌트가 적절하게 구현되었습니다.flex 레이아웃과 타이포그래피 스타일이 올바르게 정의되어 있습니다.
참고: Line 8에서는 CSS 변수(
var(--color-black-main))를 사용하고, Line 18에서는 임포트된colors.white를 사용하고 있습니다. 프로젝트 전체에서 색상 참조 방식을 통일하는 것을 고려해볼 수 있습니다.src/components/common/AsideDecoration.styled.ts (1)
3-22: export 이름 충돌로 인한 유지보수성 저하 우려코드베이스 내 여러
.styled.ts파일들이 각기 다른 용도의 스타일 컴포넌트를 모두Wrapper라는 동일한 이름으로 export하고 있습니다:
Wrapper.styled.ts: 전체 레이아웃 래퍼 (full-height layout)Blank.styled.ts: 간단한 여백용 divAsideDecoration.styled.ts(현재 파일): 고정 위치 장식 요소모듈이 다르므로 기술적으로는 문제가 없지만, 코드 가독성과 유지보수 측면에서 혼란을 야기할 수 있습니다. 현재 파일의 용도를 명확히 반영하는 이름(예:
AsideWrapper,DecorationContainer)으로 변경하는 것을 권장합니다.🔎 제안: 명확한 이름으로 변경
-export const Wrapper = styled.div` +export const AsideWrapper = styled.div` position: fixed; /* 뷰포트 중앙 기준으로 왼쪽 방향으로 650px 떨어뜨림 */ left: 50%; transform: translateX(-650px); bottom: 0; z-index: 1; pointer-events: none; user-select: none; img { display: block; max-width: 100%; height: auto; } @media (max-width: 1250px) { display: none; } `;그리고 AsideDecoration.tsx에서도 import를 업데이트:
-import { Wrapper } from './AsideDecoration.styled'; +import { AsideWrapper } from './AsideDecoration.styled';src/components/feed/FeedPost.styled.ts (2)
7-8: 주석 처리된 코드 정리를 고려해주세요.min-width/max-width 값이 주석 처리되어 있습니다. 더 이상 필요하지 않다면 제거하거나, 필요한 경우 주석으로 이유를 명시해주세요.
15-23: 하드코딩된 색상 값을 CSS 변수로 교체하는 것을 권장합니다.
#1c1c1c색상이 직접 사용되고 있습니다. 일관성을 위해 CSS 변수(예:var(--color-darkgrey-dark))나colors토큰을 사용하는 것이 좋습니다.또한
94.8%너비는 특이한 값으로, 정확한 레이아웃 의도가 있다면 주석으로 설명을 추가해주세요.🔎 권장 수정
export const BorderBottom = styled.div` - width: 94.8%; + width: calc(100% - 40px); /* padding 20px * 2 제외 */ /* min-width: 280px; max-width: 500px; */ margin: 0 auto; padding: 0 20px; height: 6px; - background: #1c1c1c; + background: var(--color-darkgrey-dark); `;src/components/feed/Profile.styled.ts (1)
55-65: 색상 값 일관성을 검토해주세요.
border: 1px solid #888에서 하드코딩된 색상을 사용하고 있습니다.UserProfileItem.styled.ts에서는colors.grey[300]을 사용하고 있으므로, 일관성을 위해 CSS 변수나 토큰 사용을 권장합니다.🔎 권장 수정
.followbutton { padding: 8px 12px; border-radius: 20px; - border: 1px solid #888; + border: 1px solid var(--color-grey-300); color: var(--color-text-secondary_grey00, #dadada); font-size: var(--string-size-medium01, 14px); font-weight: var(--string-weight-medium, 500); line-height: normal; cursor: pointer; }src/components/feed/TotalFeed.styled.ts (2)
7-7: 주석 형식을 개선해주세요.
//이전 76px주석이 있습니다. 코드 가독성을 위해/* 이전: 76px */형식으로 작성하거나, 변경 이력이라면 제거하는 것이 좋습니다.🔎 권장 수정
min-height: 100vh; padding-top: 136px; - padding-bottom: 125px; //이전 76px + padding-bottom: 125px; background-color: var(--color-black-main);
4-22: 스타일 토큰 사용 방식의 일관성을 검토해주세요.
Container에서는 CSS 변수(var(--color-black-main))를 사용하고,EmptyState에서는 import된 토큰(colors.white,typography.fontSize.lg)을 사용하고 있습니다. 한 파일 내에서 일관된 방식을 사용하는 것이 유지보수에 유리합니다.src/components/feed/BookInfoCard.styled.ts (1)
8-9: 주석 처리된 코드를 정리해주세요.min-width와 max-width 속성이 주석 처리되어 있습니다. 이 코드가 향후 사용 예정이 아니라면 가독성을 위해 제거하는 것이 좋습니다. 의도적으로 남겨둔 것이라면 주석으로 이유를 설명해주시면 좋겠습니다.
🔎 정리 제안
display: flex; height: 44px; padding: 8px 4px 8px 12px; - /* min-width: 280px; - max-width: 500px; */ flex-direction: row;src/components/common/Post/ReplyList.styled.ts (1)
8-9: 주석 처리된 코드 정리 권장Container 컴포넌트에는 width 제약이 주석 처리되어 있지만, EmptyState 컴포넌트(29-30번째 줄)에는 동일한 제약이 활성화되어 있습니다. 두 컴포넌트 간 일관성을 위해 width 제약 사용 여부를 결정하고 주석을 제거하거나 적용하는 것이 좋습니다.
src/components/feed/MyFeed.tsx (2)
22-23: 사용자 대상 에러 핸들링 고려현재 프로필 로드 실패 시 콘솔에만 에러를 로깅합니다. 사용자에게 에러 상태를 표시하거나 재시도 옵션을 제공하는 것을 고려해보세요.
🔎 에러 상태 표시 예시
const MyFeed = ({ showHeader, posts = [], isLast = false }: FeedListProps) => { const [profileData, setProfileData] = useState<MyProfileData | null>(null); const [loading, setLoading] = useState(true); + const [error, setError] = useState<string | null>(null); const hasPosts = posts.length > 0; useEffect(() => { const loadProfile = async () => { try { setLoading(true); + setError(null); const response = await getMyProfile(); setProfileData(response.data); } catch (error) { console.error('프로필 정보 로드 실패:', error); + setError('프로필 정보를 불러오는데 실패했습니다.'); } finally { setLoading(false); } }; loadProfile(); }, []); + if (error) { + return <EmptyState><div>{error}</div></EmptyState>; + } + if (loading || !profileData) { return <></>; }
32-34: 로딩 중 UX 개선 고려로딩 중에 빈 프래그먼트를 반환하면 사용자에게 아무것도 표시되지 않습니다. 로딩 스피너나 스켈레톤 UI를 표시하는 것을 고려해보세요.
src/components/feed/MyFeed.styled.ts (1)
7-7: 주석을 제거하거나 영문으로 작성하세요.코드 내 한글 주석 "//이전 76px"은 제거하거나, 필요한 경우 영문으로 작성하는 것이 좋습니다. 이력 추적이 필요하다면 Git 히스토리를 활용하세요.
src/components/feed/FollowList.styled.ts (1)
18-18: 색상 및 타이포그래피 참조 방식을 통일하세요.일부 속성은 CSS 변수(
var(--color-white))를 사용하고, 다른 속성은 직접 임포트한 객체(typography.fontSize)나 하드코딩된 값(#fff)을 사용하고 있습니다. 일관성을 위해 하나의 방식으로 통일하는 것을 권장합니다.🔎 일관성을 위한 제안
58번 라인의 하드코딩된 색상을 변수로 변경:
width: 36px; overflow: hidden; - color: #fff; + color: var(--color-white); text-overflow: ellipsis;또는 프로젝트에서 CSS 변수보다 직접 임포트를 선호하는 경우 전체를 통일:
- font-size: ${typography.fontSize['2xs']}; + font-size: var(--font-size-2xs);Also applies to: 58-58, 62-62
src/components/common/Modal/ConfirmModal.styled.ts (1)
14-26: 중첩 클래스 선택자를 별도의 styled 컴포넌트로 추출하는 것을 고려하세요.
.title과.disc클래스 선택자가 Container 내부에 중첩되어 있습니다. 타입 안정성과 재사용성을 높이기 위해 별도의 styled 컴포넌트로 추출하는 것이 좋습니다.🔎 제안하는 리팩토링
export const Container = styled.div` display: flex; flex-direction: column; width: 320px; height: 182px; padding: 20px; justify-content: space-between; border-radius: 12px; background-color: ${colors.darkgrey.main}; - - .title { - color: ${colors.white}; - font-size: ${typography.fontSize.lg}; - font-weight: ${typography.fontWeight.medium}; - line-height: 24px; - } - - .disc { - color: ${colors.white}; - font-size: ${typography.fontSize.sm}; - font-weight: ${typography.fontWeight.regular}; - line-height: normal; - } `; + +export const Title = styled.div` + color: ${colors.white}; + font-size: ${typography.fontSize.lg}; + font-weight: ${typography.fontWeight.medium}; + line-height: 24px; +`; + +export const Description = styled.div` + color: ${colors.white}; + font-size: ${typography.fontSize.sm}; + font-weight: ${typography.fontWeight.regular}; + line-height: normal; +`;src/components/group/MyGroupCard.styled.ts (1)
44-55: 중첩 선택자를 별도의 styled 컴포넌트로 추출하는 것을 고려하세요.
> span선택자를 사용하는 대신, 별도의 styled 컴포넌트로 추출하면 타입 안정성과 재사용성이 향상됩니다.src/components/group/RecruitingGroupCarousel.styled.ts (1)
3-42: 코드 중복을 제거하기 위해 공통 styled 컴포넌트 추출을 고려하세요.
CarouselContainer와NavButton이src/components/group/MyGroupBox.styled.ts에도 거의 동일하게 구현되어 있습니다. 약간의 차이(positioning 값 3% vs 4%)만 있을 뿐, 대부분의 스타일이 중복됩니다.공통 carousel 스타일 모듈(예:
src/components/common/Carousel.styled.ts)로 추출하고 필요한 경우 props로 차이점을 처리하는 것을 권장합니다.src/components/group/RecruitingGroupBox.styled.ts (1)
4-24: 색상 토큰 사용 방식의 일관성을 개선하세요.이 파일은 CSS 변수(
var(--color-...))와 임포트된colors객체를 혼용하고 있습니다. 프로젝트의 다른.styled.ts파일들(예:ConfirmModal.styled.ts,MyGroupCard.styled.ts)은 주로 임포트된 디자인 토큰을 사용합니다.일관성을 위해 한 가지 접근 방식을 선택하거나, CSS 변수 사용이 특정 이유(예: 런타임 테마 전환)가 있다면 주석으로 명시하는 것이 좋습니다.
src/components/group/MyGroupBox.tsx (1)
46-53: 불필요한|| undefined패턴이 있습니다.Line 52에서
room.deadlineDate || undefined는deadlineDate가 이미 falsy 값일 때 undefined를 반환하므로|| undefined부분이 중복입니다. 빈 문자열을 undefined로 변환하려는 의도가 아니라면 제거할 수 있습니다.🔎 간소화 제안
const convertJoinedRoomToGroup = (room: JoinedRoomItem): Group => ({ id: room.roomId, title: room.roomTitle, participants: room.memberCount, coverUrl: room.bookImageUrl, progress: room.userPercentage, - deadLine: room.deadlineDate || undefined, + deadLine: room.deadlineDate ?? undefined, });또는 더 간단하게:
- deadLine: room.deadlineDate || undefined, + deadLine: room.deadlineDate,src/components/search/MostSearchedBooks.styled.ts (2)
8-8: 테마 사용의 일관성을 위해 CSS 변수 대신 colors 객체 사용을 권장합니다.Line 8에서
var(--color-black-main)을 사용하고 있지만, 같은 파일의 다른 스타일 컴포넌트들은colors.black.main을 직접 사용하고 있습니다. 일관성을 위해 테마 객체를 직접 참조하는 방식으로 통일하는 것이 좋습니다.🔎 제안하는 수정
- background-color: var(--color-black-main); + background-color: ${colors.black.main};
107-108: 파일 끝의 불필요한 빈 줄을 제거하는 것을 권장합니다.파일 끝에 2개의 빈 줄이 있습니다. 일반적으로 파일은 단일 개행 문자로 끝나는 것이 권장되지만, 프로젝트의 ESLint 설정에서 허용된다면 큰 문제는 아닙니다.
src/components/common/Modal/Snackbar.tsx (1)
3-3: 철자 오류: "Discription"을 "Description"으로 수정 권장
Discription은 "Description"의 오타입니다. Snackbar.styled.ts 파일과 함께 일관되게 수정하면 코드 가독성이 향상됩니다.
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (104)
src/components/Mypage/MenuButton.styled.tssrc/components/Mypage/MenuButton.tsxsrc/components/common/AsideDecoration.styled.tssrc/components/common/AsideDecoration.tsxsrc/components/common/Blank.styled.tssrc/components/common/Blank.tsxsrc/components/common/Fab.styled.tssrc/components/common/Fab.tsxsrc/components/common/Filter.styled.tssrc/components/common/Filter.tsxsrc/components/common/IconButton.styled.tssrc/components/common/IconButton.tsxsrc/components/common/LoadingSpinner.styled.tssrc/components/common/LoadingSpinner.tsxsrc/components/common/MainHeader.styled.tssrc/components/common/MainHeader.tsxsrc/components/common/Modal/ConfirmModal.styled.tssrc/components/common/Modal/ConfirmModal.tsxsrc/components/common/Modal/CountingBar.styled.tssrc/components/common/Modal/CountingBar.tsxsrc/components/common/Modal/ImageViewer.styled.tssrc/components/common/Modal/ImageViewer.tsxsrc/components/common/Modal/MoreMenu.styled.tssrc/components/common/Modal/MoreMenu.tsxsrc/components/common/Modal/PopupContainer.styled.tssrc/components/common/Modal/PopupContainer.tsxsrc/components/common/Modal/ReplyModal.styled.tssrc/components/common/Modal/ReplyModal.tsxsrc/components/common/Modal/Snackbar.styled.tssrc/components/common/Modal/Snackbar.tsxsrc/components/common/NavBar.styled.tssrc/components/common/NavBar.tsxsrc/components/common/Post/PostBody.styled.tssrc/components/common/Post/PostBody.tsxsrc/components/common/Post/PostFooter.styled.tssrc/components/common/Post/PostFooter.tsxsrc/components/common/Post/PostHeader.styled.tssrc/components/common/Post/PostHeader.tsxsrc/components/common/Post/Reply.styled.tssrc/components/common/Post/Reply.tsxsrc/components/common/Post/ReplyList.styled.tssrc/components/common/Post/ReplyList.tsxsrc/components/common/Post/SubReply.styled.tssrc/components/common/Post/SubReply.tsxsrc/components/common/TitleHeader.styled.tssrc/components/common/TitleHeader.tsxsrc/components/common/TokenStatus.styled.tssrc/components/common/TokenStatus.tsxsrc/components/common/Wrapper.styled.tssrc/components/common/Wrapper.tsxsrc/components/feed/BookInfoCard.styled.tssrc/components/feed/BookInfoCard.tsxsrc/components/feed/FeedDetailPost.styled.tssrc/components/feed/FeedDetailPost.tsxsrc/components/feed/FeedDetailPostBody.styled.tssrc/components/feed/FeedDetailPostBody.tsxsrc/components/feed/FeedPost.styled.tssrc/components/feed/FeedPost.tsxsrc/components/feed/FollowList.styled.tssrc/components/feed/FollowList.tsxsrc/components/feed/MyFeed.styled.tssrc/components/feed/MyFeed.tsxsrc/components/feed/MyFollower.styled.tssrc/components/feed/MyFollower.tsxsrc/components/feed/OtherFeed.styled.tssrc/components/feed/OtherFeed.tsxsrc/components/feed/Profile.styled.tssrc/components/feed/Profile.tsxsrc/components/feed/TabBar.styled.tssrc/components/feed/TabBar.tsxsrc/components/feed/TotalBar.styled.tssrc/components/feed/TotalBar.tsxsrc/components/feed/TotalFeed.styled.tssrc/components/feed/TotalFeed.tsxsrc/components/feed/UserProfileItem.styled.tssrc/components/feed/UserProfileItem.tsxsrc/components/group/GroupCard.styled.tssrc/components/group/GroupCard.tsxsrc/components/group/MyGroupBox.styled.tssrc/components/group/MyGroupBox.tsxsrc/components/group/MyGroupCard.styled.tssrc/components/group/MyGroupCard.tsxsrc/components/group/MyGroupModal.styled.tssrc/components/group/MyGroupModal.tsxsrc/components/group/PasswordModal.styled.tssrc/components/group/PasswordModal.tsxsrc/components/group/RecruitingGroupBox.styled.tssrc/components/group/RecruitingGroupBox.tsxsrc/components/group/RecruitingGroupCarousel.styled.tssrc/components/group/RecruitingGroupCarousel.tsxsrc/components/memory/UploadProgressBar/UploadProgressBar.styled.tssrc/components/memory/UploadProgressBar/UploadProgressBar.tsxsrc/components/search/BookSearchResult.styled.tssrc/components/search/BookSearchResult.tsxsrc/components/search/GroupSearchResult.styled.tssrc/components/search/GroupSearchResult.tsxsrc/components/search/IntroModal.styled.tssrc/components/search/IntroModal.tsxsrc/components/search/MostSearchedBooks.styled.tssrc/components/search/MostSearchedBooks.tsxsrc/components/search/RecentSearchTabs.styled.tssrc/components/search/RecentSearchTabs.tsxsrc/components/search/SearchBar.styled.tssrc/components/search/SearchBar.tsx
🧰 Additional context used
🧬 Code graph analysis (44)
src/components/feed/Profile.styled.ts (8)
src/components/feed/FeedDetailPost.styled.ts (1)
Container(3-13)src/components/feed/FeedDetailPostBody.styled.ts (1)
Container(3-8)src/components/feed/FeedPost.styled.ts (1)
Container(3-13)src/components/feed/FollowList.styled.ts (1)
Container(4-22)src/components/feed/MyFollower.styled.ts (1)
Container(3-51)src/components/feed/TabBar.styled.ts (1)
Container(3-18)src/components/feed/TotalBar.styled.ts (1)
Container(3-9)src/components/feed/UserProfileItem.styled.ts (1)
UserProfile(15-76)
src/components/common/TokenStatus.tsx (1)
src/components/common/TokenStatus.styled.ts (1)
Container(3-14)
src/components/common/Wrapper.styled.ts (3)
src/components/common/AsideDecoration.styled.ts (1)
Wrapper(3-22)src/components/common/Blank.styled.ts (1)
Wrapper(3-6)src/components/common/Wrapper.tsx (1)
Wrapper(1-1)
src/components/common/TokenStatus.styled.ts (8)
src/components/common/Filter.styled.ts (1)
Container(4-9)src/components/common/LoadingSpinner.styled.ts (1)
Container(4-19)src/components/common/Post/PostBody.styled.ts (1)
Container(3-9)src/components/common/Post/PostFooter.styled.ts (1)
Container(3-35)src/components/common/Post/PostHeader.styled.ts (1)
Container(3-50)src/components/common/Post/Reply.styled.ts (1)
Container(16-21)src/components/common/Post/ReplyList.styled.ts (1)
Container(4-21)src/components/common/Post/SubReply.styled.ts (1)
Container(16-21)
src/components/Mypage/MenuButton.styled.ts (1)
src/styles/global/global.ts (2)
colors(4-53)typography(56-77)
src/components/common/Post/PostBody.styled.ts (2)
src/components/common/Post/PostFooter.styled.ts (1)
Container(3-35)src/components/common/Post/PostHeader.styled.ts (1)
Container(3-50)
src/components/common/Post/PostHeader.styled.ts (8)
src/components/common/Filter.styled.ts (1)
Container(4-9)src/components/common/LoadingSpinner.styled.ts (1)
Container(4-19)src/components/common/Post/PostBody.styled.ts (1)
Container(3-9)src/components/common/Post/PostFooter.styled.ts (1)
Container(3-35)src/components/common/Post/Reply.styled.ts (1)
Container(16-21)src/components/common/Post/ReplyList.styled.ts (1)
Container(4-21)src/components/common/Post/SubReply.styled.ts (1)
Container(16-21)src/components/common/TokenStatus.styled.ts (1)
Container(3-14)
src/components/common/LoadingSpinner.styled.ts (1)
src/styles/global/global.ts (2)
colors(4-53)typography(56-77)
src/components/feed/FeedDetailPostBody.styled.ts (3)
src/components/feed/FeedDetailPost.styled.ts (1)
Container(3-13)src/components/feed/Profile.styled.ts (1)
Container(3-13)src/components/feed/TotalBar.styled.ts (1)
Container(3-9)
src/components/feed/UserProfileItem.styled.ts (2)
src/styles/global/global.ts (2)
colors(4-53)typography(56-77)src/components/feed/Profile.styled.ts (1)
UserProfile(15-66)
src/components/common/Modal/CountingBar.styled.ts (1)
src/styles/global/global.ts (2)
colors(4-53)typography(56-77)
src/components/feed/MyFeed.styled.ts (1)
src/styles/global/global.ts (2)
colors(4-53)typography(56-77)
src/components/search/MostSearchedBooks.styled.ts (1)
src/styles/global/global.ts (2)
typography(56-77)colors(4-53)
src/components/feed/TotalFeed.styled.ts (1)
src/styles/global/global.ts (2)
colors(4-53)typography(56-77)
src/components/common/MainHeader.styled.ts (1)
src/components/common/TitleHeader.styled.ts (1)
HeaderWrapper(4-14)
src/components/memory/UploadProgressBar/UploadProgressBar.styled.ts (1)
src/styles/global/global.ts (3)
semanticColors(80-153)typography(56-77)colors(4-53)
src/components/common/Modal/MoreMenu.styled.ts (1)
src/styles/global/global.ts (2)
colors(4-53)typography(56-77)
src/components/common/AsideDecoration.styled.ts (3)
src/components/common/Blank.styled.ts (1)
Wrapper(3-6)src/components/common/Wrapper.styled.ts (1)
Wrapper(3-14)src/components/common/Wrapper.tsx (1)
Wrapper(1-1)
src/components/common/Modal/ReplyModal.styled.ts (3)
src/components/common/Modal/MoreMenu.styled.ts (1)
Overlay(4-20)src/components/common/Modal/ImageViewer.styled.ts (1)
ModalContainer(18-27)src/styles/global/global.ts (2)
colors(4-53)typography(56-77)
src/components/search/BookSearchResult.styled.ts (1)
src/styles/global/global.ts (2)
colors(4-53)typography(56-77)
src/components/feed/TotalBar.styled.ts (10)
src/components/feed/FeedDetailPost.styled.ts (1)
Container(3-13)src/components/feed/FeedDetailPostBody.styled.ts (1)
Container(3-8)src/components/feed/FeedPost.styled.ts (1)
Container(3-13)src/components/feed/FollowList.styled.ts (1)
Container(4-22)src/components/feed/MyFeed.styled.ts (1)
Container(4-9)src/components/feed/MyFollower.styled.ts (1)
Container(3-51)src/components/feed/OtherFeed.styled.ts (1)
Container(4-9)src/components/feed/Profile.styled.ts (1)
Container(3-13)src/components/feed/TabBar.styled.ts (1)
Container(3-18)src/components/feed/TotalFeed.styled.ts (1)
Container(4-9)
src/components/common/Post/SubReply.styled.ts (2)
src/components/common/Post/Reply.styled.ts (3)
DeletedContainer(4-14)Container(16-21)ReplySection(23-62)src/styles/global/global.ts (2)
colors(4-53)typography(56-77)
src/components/common/Modal/Snackbar.styled.ts (3)
src/components/common/Modal/ConfirmModal.styled.ts (2)
Container(4-27)Button(35-47)src/styles/global/global.ts (2)
colors(4-53)typography(56-77)src/components/common/Modal/MoreMenu.styled.ts (1)
Button(48-103)
src/components/group/MyGroupCard.styled.ts (2)
src/components/group/GroupCard.styled.ts (2)
Card(4-22)Info(58-64)src/styles/global/global.ts (2)
typography(56-77)colors(4-53)
src/components/common/Blank.styled.ts (1)
src/components/common/Wrapper.styled.ts (1)
Wrapper(3-14)
src/components/group/MyGroupModal.styled.ts (4)
src/components/group/RecruitingGroupBox.styled.ts (3)
TabContainer(34-46)Tab(48-59)EmptySubText(92-98)src/styles/global/global.ts (2)
typography(56-77)colors(4-53)src/components/group/PasswordModal.styled.ts (1)
ErrorMessage(46-51)src/components/group/MyGroupBox.styled.ts (1)
EmptyTitle(153-159)
src/components/common/Modal/ImageViewer.styled.ts (1)
src/styles/global/global.ts (1)
colors(4-53)
src/components/search/GroupSearchResult.styled.ts (3)
src/components/search/RecentSearchTabs.styled.ts (2)
TabContainer(17-21)Tab(23-29)src/styles/global/global.ts (2)
typography(56-77)colors(4-53)src/components/search/IntroModal.styled.ts (1)
Content(48-54)
src/components/common/Filter.styled.ts (2)
src/components/common/Filter.tsx (2)
Text(46-46)SelectedText(46-46)src/styles/global/global.ts (2)
colors(4-53)typography(56-77)
src/components/group/RecruitingGroupBox.styled.ts (1)
src/styles/global/global.ts (2)
typography(56-77)colors(4-53)
src/components/group/GroupCard.styled.ts (1)
src/styles/global/global.ts (2)
colors(4-53)typography(56-77)
src/components/group/MyGroupBox.styled.ts (2)
src/styles/global/global.ts (2)
colors(4-53)typography(56-77)src/components/group/RecruitingGroupCarousel.styled.ts (2)
CarouselContainer(3-13)NavButton(15-42)
src/components/search/RecentSearchTabs.styled.ts (4)
src/components/search/BookSearchResult.styled.ts (1)
Title(45-56)src/components/search/IntroModal.styled.ts (1)
Title(42-46)src/styles/global/global.ts (2)
colors(4-53)typography(56-77)src/components/search/GroupSearchResult.styled.ts (2)
TabContainer(4-10)Tab(12-22)
src/components/common/Modal/ConfirmModal.styled.ts (3)
src/components/common/Modal/Snackbar.styled.ts (2)
Container(4-26)Button(34-39)src/styles/global/global.ts (2)
colors(4-53)typography(56-77)src/components/common/Modal/MoreMenu.styled.ts (1)
Button(48-103)
src/components/common/Modal/Snackbar.tsx (1)
src/stores/usePopupStore.ts (1)
SnackbarProps(30-37)
src/components/feed/BookInfoCard.styled.ts (1)
src/styles/global/global.ts (2)
colors(4-53)typography(56-77)
src/components/group/PasswordModal.styled.ts (2)
src/styles/global/global.ts (2)
colors(4-53)typography(56-77)src/components/group/MyGroupModal.styled.ts (1)
ErrorMessage(48-55)
src/components/common/TitleHeader.styled.ts (2)
src/components/common/MainHeader.styled.ts (1)
HeaderWrapper(3-15)src/styles/global/global.ts (1)
colors(4-53)
src/components/group/RecruitingGroupCarousel.styled.ts (1)
src/components/group/MyGroupBox.styled.ts (2)
CarouselContainer(35-43)NavButton(45-72)
src/components/common/Post/PostFooter.styled.ts (1)
src/components/common/Post/PostHeader.styled.ts (1)
Container(3-50)
src/components/feed/MyFollower.styled.ts (2)
src/components/feed/FeedPost.styled.ts (1)
Container(3-13)src/components/feed/FollowList.styled.ts (1)
Container(4-22)
src/components/common/Post/ReplyList.styled.ts (1)
src/styles/global/global.ts (2)
colors(4-53)typography(56-77)
src/components/feed/FollowList.styled.ts (1)
src/styles/global/global.ts (1)
typography(56-77)
src/components/search/IntroModal.styled.ts (1)
src/styles/global/global.ts (2)
colors(4-53)typography(56-77)
| fullHeight && | ||
| ` | ||
| min-height: 100vh; | ||
| background-color: var(--color-black-main); |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
CSS 변수 대신 import된 토큰을 사용하세요.
var(--color-black-main) 대신 import된 colors.black.main을 사용하여 일관성을 유지하세요. 같은 파일의 Line 36에서는 colors.white를 사용하고 있습니다.
🔎 제안하는 수정
min-height: 100vh;
- background-color: var(--color-black-main);
+ background-color: ${colors.black.main};
`}🤖 Prompt for AI Agents
In src/components/common/LoadingSpinner.styled.ts around line 17, the
background-color uses the CSS variable var(--color-black-main); replace this
with the imported token colors.black.main to match the rest of the file (line 36
uses colors.white). Update the property to use colors.black.main, and if not
already present, add the colors import at the top of the file (import { colors }
from '...') or use the existing import style used elsewhere in the project;
ensure no var(...) remains and run a quick lint/style check.
| align-items: flex-start; | ||
| align-items: center; |
There was a problem hiding this comment.
중복된 align-items 속성을 수정하세요.
28번과 29번 라인에 align-items 속성이 중복 선언되어 있습니다. 두 번째 선언(center)이 첫 번째 선언(flex-start)을 덮어쓰게 됩니다. 의도한 정렬 방식이 무엇인지 확인하고 하나만 남기세요.
🔎 제안하는 수정
center 정렬이 의도된 경우:
pointer-events: none;
display: flex;
- align-items: flex-start;
align-items: center;
min-width: 320px;또는 flex-start가 의도된 경우:
pointer-events: none;
display: flex;
align-items: flex-start;
- align-items: center;
min-width: 320px;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| align-items: flex-start; | |
| align-items: center; | |
| pointer-events: none; | |
| display: flex; | |
| align-items: center; | |
| min-width: 320px; |
| align-items: flex-start; | |
| align-items: center; | |
| pointer-events: none; | |
| display: flex; | |
| align-items: flex-start; | |
| min-width: 320px; |
🤖 Prompt for AI Agents
In src/components/common/Modal/PopupContainer.styled.ts around lines 28-29 there
are duplicate align-items declarations (align-items: flex-start; and
align-items: center;) causing the second to override the first; decide which
alignment is intended and remove the other declaration so only the correct
align-items remains (e.g., keep align-items: center; if center is desired, or
keep align-items: flex-start; if top alignment is desired).
| export const NavContainer = styled.div` | ||
| position: fixed; | ||
| bottom: 0; | ||
| left: 0; | ||
| right: 0; | ||
| display: flex; | ||
| justify-content: space_between; | ||
| align-items: center; | ||
| margin: 0 auto; | ||
| min-width: 320px; | ||
| max-width: 767px; | ||
| height: 75px; | ||
| padding: 16px 32px; | ||
| border-top: 1px solid var(--color-grey-300); | ||
| border-radius: 12px 12px 0px 0px; | ||
| background-color: var(--color-black-main); | ||
| `; |
There was a problem hiding this comment.
CSS 속성 값 오타를 수정해주세요.
Line 13의 justify-content: space_between;에서 space_between은 유효하지 않은 CSS 값입니다. 올바른 값은 space-between(하이픈 사용)입니다. 이 오타로 인해 NavContainer의 flex 레이아웃이 의도대로 작동하지 않습니다.
🔎 수정 제안
display: flex;
- justify-content: space_between;
+ justify-content: space-between;
align-items: center;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const NavContainer = styled.div` | |
| position: fixed; | |
| bottom: 0; | |
| left: 0; | |
| right: 0; | |
| display: flex; | |
| justify-content: space_between; | |
| align-items: center; | |
| margin: 0 auto; | |
| min-width: 320px; | |
| max-width: 767px; | |
| height: 75px; | |
| padding: 16px 32px; | |
| border-top: 1px solid var(--color-grey-300); | |
| border-radius: 12px 12px 0px 0px; | |
| background-color: var(--color-black-main); | |
| `; | |
| export const NavContainer = styled.div` | |
| position: fixed; | |
| bottom: 0; | |
| left: 0; | |
| right: 0; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin: 0 auto; | |
| min-width: 320px; | |
| max-width: 767px; | |
| height: 75px; | |
| padding: 16px 32px; | |
| border-top: 1px solid var(--color-grey-300); | |
| border-radius: 12px 12px 0px 0px; | |
| background-color: var(--color-black-main); | |
| `; |
🤖 Prompt for AI Agents
In src/components/common/NavBar.styled.ts around lines 7 to 25, the CSS property
value on line 13 is invalid: `justify-content: space_between;` uses an
underscore instead of a hyphen; change it to the correct CSS value
`space-between` so the flex layout works as intended and update any related
formatting if necessary.
| export const NextButton = styled.div<{ active: boolean }>` | ||
| cursor: ${({ active }) => (active ? 'pointer' : 'default')}; | ||
| width: 49px; | ||
| height: 28px; | ||
| padding: 4px 12px; | ||
| border-radius: 20px; | ||
| background-color: ${({ active }) => | ||
| active ? 'var(--color-purple-main)' : 'var(--color-grey-300)'}; | ||
| color: var(--color-white); | ||
| font-size: var(--font-size-sm); | ||
| font-weight: var(--font-weight-semibold); | ||
| line-height: 20px; | ||
| text-align: center; | ||
| `; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for TitleHeader component definition and usage
# First, find the TitleHeader component file
echo "=== Finding TitleHeader component ==="
find . -type f \( -name "*.ts" -o -name "*.tsx" \) | xargs grep -l "export.*TitleHeader" | head -20
# Search for TitleHeader usage with rightButton prop
echo -e "\n=== TitleHeader usages with rightButton prop ==="
rg -n "TitleHeader" --type=tsx --type=ts -A 3 -B 2 | head -100Repository: THIP-TextHip/THIP-Web
Length of output: 237
🏁 Script executed:
#!/bin/bash
# More specific search for rightButton prop values
echo "=== Searching for rightButton prop assignments ==="
rg -n "rightButton\s*=" --type=tsx --type=ts -B 2 -A 1 | head -80
echo -e "\n=== Searching for TitleHeader with rightButton ==="
rg -n -A 5 "rightButton" --type=tsx --type=ts | grep -E "(rightButton|TitleHeader)" | head -100Repository: THIP-TextHip/THIP-Web
Length of output: 240
🏁 Script executed:
#!/bin/bash
# Find all component files that use TitleHeader
echo "=== Files importing TitleHeader ==="
rg -l "from.*TitleHeader|import.*TitleHeader" --type=tsx --type=ts
echo -e "\n=== TitleHeader component definition ==="
fd "TitleHeader" --type f \( -name "*.ts" -o -name "*.tsx" \) | grep -v node_modulesRepository: THIP-TextHip/THIP-Web
Length of output: 418
🏁 Script executed:
#!/bin/bash
# Read TitleHeader component definition
echo "=== TitleHeader.tsx content ==="
cat -n ./src/components/common/TitleHeader.tsx | head -100Repository: THIP-TextHip/THIP-Web
Length of output: 1540
🏁 Script executed:
#!/bin/bash
# Search for TitleHeader usages and rightButton prop
echo "=== Searching for rightButton prop usage ==="
rg -n "rightButton" --type js --type ts -A 2 -B 2
echo -e "\n=== Searching for TitleHeader usages ==="
rg -n "TitleHeader" --type js --type ts -A 3 | head -150Repository: THIP-TextHip/THIP-Web
Length of output: 16370
🏁 Script executed:
#!/bin/bash
# Find all files that import or use TitleHeader
echo "=== Files importing TitleHeader ==="
rg -l "TitleHeader" --type js --type ts
echo -e "\n=== Files in components/common directory ==="
ls -la ./src/components/common/ | grep -E "\.(ts|tsx)$"Repository: THIP-TextHip/THIP-Web
Length of output: 2820
🏁 Script executed:
#!/bin/bash
# Read the entire TitleHeader.styled.ts file
cat -n ./src/components/common/TitleHeader.styled.tsRepository: THIP-TextHip/THIP-Web
Length of output: 1576
NextButton의 고정 너비와 텍스트 오버플로우 처리 부재
현재 모든 rightButton 텍스트가 "다음"이나 "완료"처럼 짧은 2글자이므로 49px 너비 내에서 정상 표시되지만, 오버플로우 처리 없이 고정 너비를 사용하고 있습니다. 향후 더 긴 텍스트가 전달될 경우 텍스트가 잘릴 가능성이 있으므로, NextButton에 white-space: nowrap, text-overflow: ellipsis, overflow: hidden 속성을 추가하거나 너비를 동적으로 조정하는 방식을 고려하세요.
🤖 Prompt for AI Agents
In src/components/common/TitleHeader.styled.ts around lines 16 to 29, the
NextButton uses a fixed width (49px) without any overflow handling which will
cause longer labels to be clipped; update the styling to either allow flexible
width (e.g., remove fixed width and use min-width/max-width) or keep a max-width
and add overflow handling by including white-space: nowrap, overflow: hidden,
and text-overflow: ellipsis so longer text is truncated with an ellipsis while
preserving layout.
| /* ✅ 스크롤바 숨기기 */ | ||
| scrollbar-width: none; /* Firefox */ | ||
| -ms-overflow-style: none; /* IE, Edge */ | ||
| .followerList::-webkit-scrollbar { |
There was a problem hiding this comment.
::-webkit-scrollbar 선택자를 수정하세요.
.followerList::-webkit-scrollbar는 .followerList 내부에서 .followerList라는 자식 요소를 찾으려고 시도합니다. 현재 요소 자체를 타겟팅하려면 &::-webkit-scrollbar를 사용해야 합니다.
🔎 제안하는 수정
/* ✅ 스크롤바 숨기기 */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE, Edge */
- .followerList::-webkit-scrollbar {
+ &::-webkit-scrollbar {
display: none; /* Chrome, Safari */
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| .followerList::-webkit-scrollbar { | |
| /* ✅ 스크롤바 숨기기 */ | |
| scrollbar-width: none; /* Firefox */ | |
| -ms-overflow-style: none; /* IE, Edge */ | |
| &::-webkit-scrollbar { | |
| display: none; /* Chrome, Safari */ | |
| } |
🤖 Prompt for AI Agents
In src/components/feed/FollowList.styled.ts around line 44, the selector
`.followerList::-webkit-scrollbar` is targeting a child element instead of the
component itself; change that selector to `&::-webkit-scrollbar` inside the
`.followerList` styled rule (i.e., replace `.followerList::-webkit-scrollbar`
with `&::-webkit-scrollbar`) so the scrollbar styling applies to the element
itself.
| export const CardTitle = styled.h2` | ||
| font-size: ${typography.fontSize.lg}; | ||
| font-weight: ${typography.fontWeight.semibold}; | ||
| color: #000; | ||
| margin: 0; | ||
| white-space: nowrap; | ||
| overflow: hidden; | ||
| text-overflow: ellipsis; | ||
| `; |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
하드코딩된 색상을 디자인 토큰으로 교체하세요.
color: #000이 하드코딩되어 있습니다. colors.black.main을 사용하여 일관성을 유지하세요.
🔎 제안하는 수정
export const CardTitle = styled.h2`
font-size: ${typography.fontSize.lg};
font-weight: ${typography.fontWeight.semibold};
- color: #000;
+ color: ${colors.black.main};
margin: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
`;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const CardTitle = styled.h2` | |
| font-size: ${typography.fontSize.lg}; | |
| font-weight: ${typography.fontWeight.semibold}; | |
| color: #000; | |
| margin: 0; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| `; | |
| export const CardTitle = styled.h2` | |
| font-size: ${typography.fontSize.lg}; | |
| font-weight: ${typography.fontWeight.semibold}; | |
| color: ${colors.black.main}; | |
| margin: 0; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| `; |
🤖 Prompt for AI Agents
In src/components/group/MyGroupCard.styled.ts around lines 34 to 42, the
CardTitle component hardcodes color: #000; replace this with the design token
colors.black.main to maintain consistency; update the styled component to import
and use the colors token (colors.black.main) instead of the hex literal and
ensure imports remain organized.
| background: var(--color-main-black); | ||
| border-radius: 12px; | ||
| margin-bottom: 76px; | ||
| background: var( | ||
| --gradient_card-carousel_groupmain, | ||
| linear-gradient( | ||
| 180deg, | ||
| var(--color-view-card_background_grey03, #525252) 0%, | ||
| var(--color-button-color_fill-button_fill_black, #121212) 100% | ||
| ) | ||
| ); |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
중복된 background 선언을 제거하세요.
Line 13의 background: var(--color-main-black);가 lines 16-23의 gradient background에 의해 즉시 덮어쓰여집니다. 중복 선언을 제거하세요.
🔎 제안하는 수정
width: 100%;
overflow-x: hidden;
padding: 20px 0;
- background: var(--color-main-black);
border-radius: 12px;
margin-bottom: 76px;
background: var(
--gradient_card-carousel_groupmain,
linear-gradient(
180deg,
var(--color-view-card_background_grey03, #525252) 0%,
var(--color-button-color_fill-button_fill_black, #121212) 100%
)
);
`;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| background: var(--color-main-black); | |
| border-radius: 12px; | |
| margin-bottom: 76px; | |
| background: var( | |
| --gradient_card-carousel_groupmain, | |
| linear-gradient( | |
| 180deg, | |
| var(--color-view-card_background_grey03, #525252) 0%, | |
| var(--color-button-color_fill-button_fill_black, #121212) 100% | |
| ) | |
| ); | |
| border-radius: 12px; | |
| margin-bottom: 76px; | |
| background: var( | |
| --gradient_card-carousel_groupmain, | |
| linear-gradient( | |
| 180deg, | |
| var(--color-view-card_background_grey03, #525252) 0%, | |
| var(--color-button-color_fill-button_fill_black, #121212) 100% | |
| ) | |
| ); |
🤖 Prompt for AI Agents
In src/components/group/RecruitingGroupBox.styled.ts around lines 13 to 23,
remove the redundant "background: var(--color-main-black);" on line 13 because
it is immediately overridden by the gradient background declared on lines 16-23;
keep the gradient declaration (with its fallback variables) and delete the
duplicate single-color background line to eliminate the redundant style.
| export const Title = styled.h2` | ||
| color: #fff; | ||
| font-size: ${typography.fontSize.lg}; | ||
| font-weight: ${typography.fontWeight.bold}; | ||
| margin-bottom: 32px; | ||
| text-align: center; | ||
| `; |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
하드코딩된 색상을 디자인 토큰으로 교체하세요.
#fff 색상이 하드코딩되어 있습니다. colors.white를 사용하여 일관성을 유지하세요.
🔎 제안하는 수정
export const Title = styled.h2`
- color: #fff;
+ color: ${colors.white};
font-size: ${typography.fontSize.lg};
font-weight: ${typography.fontWeight.bold};
margin-bottom: 32px;
text-align: center;
`; export const Tab = styled.button<{ selected?: boolean }>`
white-space: nowrap;
padding: 8px 12px;
font-size: ${typography.fontSize.xs};
font-weight: ${typography.fontWeight.regular};
border: none;
border-radius: 16px;
background: ${({ selected }) =>
selected ? 'var(--color-purple-main)' : 'var(--color-darkgrey-main)'};
- color: #fff;
+ color: ${colors.white};
cursor: pointer;
`;Also applies to: 48-59
🤖 Prompt for AI Agents
In src/components/group/RecruitingGroupBox.styled.ts around lines 26-32 (and
also apply the same change to lines 48-59), replace the hardcoded color "#fff"
with the design token colors.white; ensure the file imports the colors object
from the design tokens module (or add the import if missing) and update any
other hardcoded white usages in the specified range to use colors.white for
consistency.
| export const Overlay = styled.div` | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 20px; | ||
| position: fixed; | ||
| inset: 0; | ||
| background: rgba(0, 0, 0, 0.1); | ||
| backdrop-filter: blur(2.5px); | ||
| z-index: 999; | ||
| display: flex; | ||
| justify-content: center; | ||
| align-items: center; | ||
| `; |
There was a problem hiding this comment.
중복된 CSS 속성을 제거하세요.
display: flex 속성이 Line 5와 Line 13에서 중복 선언되어 있습니다. 중복을 제거하여 코드 가독성을 개선하세요.
🔎 수정 제안
export const Overlay = styled.div`
- display: flex;
flex-direction: column;
gap: 20px;
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.1);
backdrop-filter: blur(2.5px);
z-index: 999;
display: flex;
justify-content: center;
align-items: center;
`;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const Overlay = styled.div` | |
| display: flex; | |
| flex-direction: column; | |
| gap: 20px; | |
| position: fixed; | |
| inset: 0; | |
| background: rgba(0, 0, 0, 0.1); | |
| backdrop-filter: blur(2.5px); | |
| z-index: 999; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| `; | |
| export const Overlay = styled.div` | |
| flex-direction: column; | |
| gap: 20px; | |
| position: fixed; | |
| inset: 0; | |
| background: rgba(0, 0, 0, 0.1); | |
| backdrop-filter: blur(2.5px); | |
| z-index: 999; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| `; |
🤖 Prompt for AI Agents
In src/components/search/IntroModal.styled.ts around lines 4 to 16, the CSS
property "display: flex" is declared twice (line 5 and line 13); remove the
duplicate declaration (only keep a single "display: flex") to eliminate
redundancy and improve readability, ensuring the remaining properties and
ordering are unchanged.
| .delete-btn { | ||
| opacity: 0; | ||
| pointer-events: none; | ||
| transition: opacity 0.2s; | ||
| } | ||
| &:focus-within .delete-btn { | ||
| opacity: 1; | ||
| pointer-events: auto; | ||
| } |
There was a problem hiding this comment.
사용되지 않는 .delete-btn 스타일을 확인하세요.
.delete-btn 클래스에 대한 스타일이 정의되어 있지만, SearchBar.tsx의 삭제 버튼(Line 44)에는 이 클래스가 적용되어 있지 않습니다. 삭제 버튼은 value && !isSearched 조건으로 렌더링 여부만 제어되고 있어, 이 CSS 스타일은 실제로 적용되지 않습니다.
리팩토링 과정에서 의도했던 동작(focus 시 삭제 버튼 표시)이 누락되었거나, 불필요한 코드가 남아있는 것으로 보입니다.
🔎 확인이 필요한 사항
다음 중 하나를 선택하여 수정이 필요합니다:
옵션 1: 삭제 버튼에 클래스를 추가하여 CSS가 작동하도록 수정 (SearchBar.tsx에서):
<IconButton
className="delete-btn"
src={deleteIcon}
alt="입력 지우기"
onClick={() => onChange?.('')}
/>옵션 2: 현재 조건부 렌더링 방식을 유지하려면, 사용되지 않는 .delete-btn 스타일을 제거:
- .delete-btn {
- opacity: 0;
- pointer-events: none;
- transition: opacity 0.2s;
- }
- &:focus-within .delete-btn {
- opacity: 1;
- pointer-events: auto;
- }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| .delete-btn { | |
| opacity: 0; | |
| pointer-events: none; | |
| transition: opacity 0.2s; | |
| } | |
| &:focus-within .delete-btn { | |
| opacity: 1; | |
| pointer-events: auto; | |
| } |
🤖 Prompt for AI Agents
In src/components/search/SearchBar.styled.ts around lines 15-23 the .delete-btn
CSS is defined but never applied; update SearchBar.tsx (around the delete button
at line ~44) to add className="delete-btn" to the IconButton so the focus-within
show/hide behavior works, or if you prefer to keep the current conditional
rendering remove the unused .delete-btn block from this styled file to avoid
dead CSS.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
src/components/feed/Profile.tsx (1)
67-67: 접근성 개선: img 태그에 alt 속성을 추가하세요.프로필 이미지에
alt속성이 누락되어 스크린 리더 사용자에게 적절한 정보를 제공하지 못합니다.🔎 제안하는 수정사항
- <img src={profileImageUrl} /> + <img src={profileImageUrl} alt={`${nickname}의 프로필 이미지`} />src/components/common/Modal/ReplyModal.tsx (2)
73-81: 삭제/신고 권한 로직이 반대로 구현됨 (심각한 보안 문제)현재 구현은 본인 댓글일 때(
isMyReply === true) "신고하기"를 표시하고, 타인 댓글일 때(isMyReply === false) "삭제하기"를 표시합니다. 이는 의도와 반대로 동작하며, 사용자가 타인의 댓글을 삭제할 수 있고 본인 댓글은 삭제할 수 없는 치명적인 권한 오류입니다.🔎 권한 로직 수정안
<ModalContent> - {isMyReply ? ( - <OptionItem className="report"> - <div className="option-text">신고하기</div> - </OptionItem> - ) : ( + {isMyReply ? ( <OptionItem onClick={handleDelete} className="delete"> <div className="option-text">삭제하기</div> </OptionItem> + ) : ( + <OptionItem className="report"> + <div className="option-text">신고하기</div> + </OptionItem> )} </ModalContent>
36-36: 프로덕션 환경의 console.log 제거 권장프로덕션 코드에서
console.log는 제거하거나 적절한 로깅 서비스로 대체하는 것이 좋습니다.🔎 제거 제안
try { await deleteComment(commentId); - console.log('댓글 삭제 성공:', commentId); openSnackbar({src/components/common/Modal/Snackbar.tsx (1)
15-25: 타이머 충돌로 인한 예상치 못한 동작 발생 가능
Snackbar컴포넌트의 타이머와PopupContainer의 타이머가 충돌합니다:
- PopupContainer.tsx (line 33): 모든 snackbar를 5초 후
closePopup()호출- Snackbar.tsx (lines 18-22):
variant='bottom': 5초 표시 → fade-out → 2초 후onClose()호출 (총 ~7초)variant='top': 2초 표시 → fade-out → 2초 후onClose()호출 (총 ~4초)문제점:
variant='bottom'의 경우: PopupContainer가 5초에 닫지만 Snackbar는 7초를 기대 → fade-out 애니메이션이 중간에 끊김- 두 타이머가 같은 close 함수를 호출하는 race condition
- PR 목표에서 "동작 변화 없음"이라고 했으나, 이 타이밍 로직이 새로 추가된 것이라면 동작이 변경됨
권장 사항:
타이밍 제어를 한 곳에서만 수행하도록 통합해야 합니다. 두 가지 옵션이 있습니다:
- PopupContainer의 5초 타이머를 제거하고 Snackbar가 자체적으로 닫도록 함
- Snackbar의 타이머를 제거하고 PopupContainer가 모든 타이밍을 제어하도록 함
🔎 해결 방안 예시
옵션 1: Snackbar가 자체 타이밍 제어 (권장)
PopupContainer.tsx에서 snackbar 타이머 제거:
useEffect(() => { - if (isOpen && popupType === 'snackbar') { - const timer = setTimeout(() => closePopup(), 5000); - return () => clearTimeout(timer); - } }, [isOpen, popupType, closePopup]);옵션 2: PopupContainer가 모든 타이밍 제어
Snackbar.tsx의 자동 닫힘 로직 제거하고 부모가 제어:
useEffect(() => { setVisible(true); - - const showDuration = variant === 'bottom' ? 5000 : 2000; - const timer = setTimeout(() => { - setVisible(false); - setTimeout(() => onClose(), 2000); - }, showDuration); - - return () => clearTimeout(timer); }, [variant, onClose]);그리고 PopupContainer에서 variant별 타이밍 처리.
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (8)
src/components/common/MainHeader.tsxsrc/components/common/Modal/ConfirmModal.tsxsrc/components/common/Modal/MoreMenu.tsxsrc/components/common/Modal/PopupContainer.tsxsrc/components/common/Modal/ReplyModal.tsxsrc/components/common/Modal/Snackbar.tsxsrc/components/feed/Profile.tsxsrc/components/feed/UserProfileItem.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
- src/components/common/Modal/MoreMenu.tsx
- src/components/feed/UserProfileItem.tsx
- src/components/common/MainHeader.tsx
- src/components/common/Modal/ConfirmModal.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
src/components/common/Modal/Snackbar.tsx (1)
src/stores/popupStore.ts (1)
SnackbarProps(30-37)
🔇 Additional comments (3)
src/components/feed/Profile.tsx (1)
4-4: 스타일 분리 리팩토링이 올바르게 적용되었습니다.
Profile.styled.ts파일이 존재하고Container와UserProfile을 올바르게 export하고 있습니다. 인라인 styled 컴포넌트를 외부 파일로 분리한 접근 방식이 적절하게 구현되었습니다.src/components/common/Modal/ReplyModal.tsx (1)
4-4: styled 컴포넌트 분리 확인 완료ReplyModal.styled.ts 파일이 존재하며, 필요한 모든 styled 컴포넌트(Overlay, ModalContainer, ModalContent, OptionItem)가 올바르게 export되고 있습니다. 스타일 분리 리팩토링이 제대로 구성되어 있습니다.
src/components/common/Modal/PopupContainer.tsx (1)
15-15: 스타일 분리 리팩터링 적절합니다.styled 컴포넌트들을 별도 파일로 분리한 것은 코드 구조 개선에 도움이 됩니다. 임포트가 올바르게 적용되었습니다.
| import { useEffect, useState } from 'react'; | ||
|
|
||
| const Snackbar = ({ message, actionText, variant, isError, onActionClick, onClose }: SnackbarProps) => { | ||
| import { Container, Discription, Button } from './Snackbar.styled'; |
There was a problem hiding this comment.
오타 수정 필요: "Discription" → "Description"
Discription은 오타입니다. 올바른 영문 철자는 Description입니다. 임포트와 사용처(line 29) 모두에서 일관되게 수정이 필요합니다.
🔎 수정 제안
-import { Container, Discription, Button } from './Snackbar.styled';
+import { Container, Description, Button } from './Snackbar.styled';그리고 line 29도 함께 수정:
- <Discription isError={isError}>{message}</Discription>
+ <Description isError={isError}>{message}</Description>Snackbar.styled.ts 파일의 export 이름도 동일하게 수정해야 합니다.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/components/common/Modal/Snackbar.tsx around line 3, the imported symbol
"Discription" is misspelled and should be "Description"; update the import to
"Description" and update its usage at line 29 accordingly, then open
src/components/common/Modal/Snackbar.styled.ts and rename the exported
identifier from "Discription" to "Description" (and update any internal
references/exports) so the import and export names match.
#️⃣연관된 이슈
https://thip2025.atlassian.net/browse/THIP2025-397?atlOrigin=eyJpIjoiNDkyNGIzMjcwMDg2NDMwMDhjYWVmNWQ3MzkzOWNjOWEiLCJwIjoiaiJ9
📝작업 내용
개별 컴포넌트 파일에서 styled 블록을 분리해 .styled.ts로 이동 => UI/로직 변경 없이 가독성, 유지보수성, 재사용성 향상
변경된 TSX는 대응하는 .styled.ts를 임포트하도록 수정
변경 파일 기준 ESLint 오류 없음
변경내용
[feed]
BookInfoCard, FeedPost, FeedDetailPost, FeedDetailPostBody, FollowList, MyFeed, MyFollower, OtherFeed, Profile, TabBar, TotalBar, TotalFeed, UserProfileItem
[group]
GroupCard, MyGroupCard, MyGroupBox, MyGroupModal, PasswordModal, RecruitingGroupBox, RecruitingGroupCarousel
[search]
SearchBar, MostSearchedBooks, GroupSearchResult, BookSearchResult, RecentSearchTabs, IntroModal
[memory]
UploadProgressBar
[mypage]
MenuButton
동작변화 : 없음 (스타일 선언 위치만 분리, 컴포넌트 API/마크업 동일)
Summary by CodeRabbit
릴리스 노트
✏️ Tip: You can customize this high-level summary in your review settings.