Skip to content

THIP-397: COMPONENTS 스타일 코드 분리#302

Merged
ljh130334 merged 14 commits intoTHIP-394from
THIP-397
Jan 4, 2026
Merged

THIP-397: COMPONENTS 스타일 코드 분리#302
ljh130334 merged 14 commits intoTHIP-394from
THIP-397

Conversation

@heeeeyong
Copy link
Collaborator

@heeeeyong heeeeyong commented Jan 1, 2026

#️⃣연관된 이슈

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

릴리스 노트

  • 개선 사항
    • 메뉴 버튼에 텍스트 및 버튼 모드 옵션 추가(우측 화살표 표시 제어)
    • 헤더에 좌/우 아이콘 및 다음 버튼 지원 확장
    • 팔로워 위젯에 최근 팔로워 프로필 이미지 표시 및 상세 이동 추가
    • 내 피드에서 사용자 프로필 자동 로드 및 로딩/빈 상태 처리 개선
    • 인기 검색·검색 결과 목록에 로딩/에러/페이징 보완 및 카운트 표시(TotalBar 추가)

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

@heeeeyong heeeeyong self-assigned this Jan 1, 2026
@vercel
Copy link

vercel bot commented Jan 1, 2026

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

Project Deployment Review Updated (UTC)
thip Ready Ready Preview, Comment Jan 4, 2026 0:16am

@coderabbitai
Copy link

coderabbitai bot commented Jan 1, 2026

Walkthrough

Emotion 기반의 인라인 styled 컴포넌트들을 각 컴포넌트별 .styled.ts 파일로 대거 분리하고, 일부 컴포넌트에 props·로직(예: MyFeed 로딩, PostFooter/ReplyList props 확장, TitleHeader props 확장 등)을 추가/확장함.

Changes

Cohort / File(s) 변경 요약
Mypage 컴포넌트
src/components/Mypage/MenuButton.tsx, src/components/Mypage/MenuButton.styled.ts
MenuButton의 inline 스타일을 MenuButton.styled.ts로 이동. Props 확장: name, textColor?, isButton?.
공통 컴포넌트 (common) — 기본/단순 컴포넌트
src/components/common/Blank.*, src/components/common/Fab.*, src/components/common/IconButton.*, src/components/common/Wrapper.*, src/components/common/TokenStatus.*, src/components/common/AsideDecoration.*
각 파일의 inline styled 정의를 대응 .styled.ts로 분리(재내보내기/임포트로 변경). 렌더/동작은 동일.
공통 컴포넌트 (common) — 헤더/네비/토큰 등
src/components/common/MainHeader.*, src/components/common/NavBar.*, src/components/common/TitleHeader.*
헤더/네비 관련 styled 추출. TitleHeader는 Props 확장(좌/우 아이콘, 우측 버튼, isNextActive, 클릭 핸들러).
공통 컴포넌트 (common) — 필터/로더/플로팅/토스트 등
src/components/common/Filter.*, src/components/common/LoadingSpinner.*, src/components/common/Fab.*, src/components/common/Modal/Snackbar.*, src/components/common/Modal/CountingBar.*
여러 보조 UI(styled)들을 .styled.ts로 추출. Snackbar 등은 visible/variant 관련 props 유지.
공통 Modal 계열
src/components/common/Modal/ConfirmModal.*, ImageViewer.*, MoreMenu.*, PopupContainer.*, ReplyModal.*
모달계열의 모든 styled 정의를 전용 .styled.ts로 이동(variant·isActive 등 prop 기반 스타일 포함).
Post 관련 컴포넌트
src/components/common/Post/PostBody.*, .../PostHeader.*, .../PostFooter.*, .../Reply.*, .../ReplyList.*, .../SubReply.*
Post 계열 컴포넌트들의 styled를 외부화. PostFooter·ReplyList 등은 props(예: commentCount, feedId, onReload, isDetail 등) 확장.
Feed 관련 — 메인/리스트/카드/탭
src/components/feed/MyFeed.*, OtherFeed.*, TotalFeed.*, FeedPost.*, FeedDetailPost.*, FeedDetailPostBody.*, BookInfoCard.*, TabBar.*, TotalBar.*, FollowList.*, MyFollower.*, Profile.*, UserProfileItem.*
다수 컴포넌트의 styled를 .styled.ts로 분리. MyFeed에 데이터 로딩(useEffect/getMyProfile) 추가. MyFollower props 확장(latestFollowerProfileImageUrls?, userId?). TabBar는 ActiveIndicator 로직 포함.
Group 관련 컴포넌트
src/components/group/GroupCard.*, MyGroupBox.*, MyGroupCard.*, MyGroupModal.*, PasswordModal.*, RecruitingGroupBox.*, RecruitingGroupCarousel.*
그룹 관련 컴포넌트의 스타일 대다수를 .styled.ts로 이동. MyGroupBox에 Group 타입 및 변환 헬퍼 추가. 여러 카드/모달/캐러셀 스타일이 prop 기반으로 세분화됨.
Memory / UploadProgressBar
src/components/memory/UploadProgressBar/*
업로드 진행바의 styled 분리. ProgressBarFill에 progress prop으로 width 제어.
Search 관련 컴포넌트
src/components/search/BookSearchResult.*, GroupSearchResult.*, MostSearchedBooks.*, RecentSearchTabs.*, SearchBar.*, IntroModal.*
검색·결과·모달 관련 styled 를 외부화. BookSearchResult는 props 확장(searchedBookList, hasMore, isLoading, lastBookElementCallback, totalElements). MostSearchedBooks는 API 로드/에러 처리 추가.

Sequence Diagram(s)

(생성 조건 미충족 — 변경 대부분이 스타일 추출 및 일부 props/로직 확장으로, 다중 컴포넌트 간 새로운 제어 흐름을 시각화할 필요 없음.)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 분

Possibly related PRs

Suggested labels

🎨 Html&css

Suggested reviewers

  • ho0010

Poem

🐰 깔끔히 모듈로 나눴네, 스타일 한 상자에
작은 컴포넌트들 춤추네, .styled.ts로 향해
60개 파일 줄지어, 깡총깡총 리팩토링 축제
당근 한 입에 커밋 휙, 유지보수는 싱그럽네 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Linked Issues check ❓ Inconclusive THIP2025-397 이슈의 구체적인 요구사항 정보가 제공되지 않아 코드 변경이 요구사항을 충족하는지 명확히 검증할 수 없습니다. 연관 이슈의 상세한 요구사항(작업 범위, 완료 기준 등)을 제공하여 요구사항 충족 여부를 명확히 검증하시기 바랍니다.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 변경 사항의 핵심을 명확하게 요약하고 있습니다. 'COMPONENTS 스타일 코드 분리'는 대규모 스타일 코드 리팩토링 작업을 정확하게 반영합니다.
Out of Scope Changes check ✅ Passed 모든 변경 사항이 styled 컴포넌트를 .styled.ts 파일로 분리하는 리팩토링 범위 내에 있으며, 컴포넌트 API, 동작, 마크업의 변화는 없습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • THIP-397: Request failed with status code 404

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.

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: 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: 삭제/신고 로직이 반대로 구현되어 있습니다.

조건부 렌더링 로직에 심각한 오류가 있습니다:

  • isMyReplytrue(내 댓글)일 때 "신고하기"가 표시됩니다.
  • isMyReplyfalse(타인의 댓글)일 때 "삭제하기"가 표시되고 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 핸들러를 전달합니다:

  1. 첫 번째 사용 (162-166): onClick={() => navigate(\detail/joined/${groups[0].id}`)}- deadline이 있으면/group/detail/{id}`로 네비게이션되어 의도한 경로와 다름
  2. 두 번째 사용 (177-185): onClick={() => handleCardClick(g.id)} - deadline이 있으면 onClick이 호출되지 않음

이 동작 변경은 deadline 있는/없는 그룹의 처리 방식을 근본적으로 달리하므로, 다음을 명확히 해야 합니다:

  • hasDeadline 여부와 관계없이 동일하게 동작해야 하는지, 아니면 의도적으로 다르게 처리하려는 것인지
  • 부모 컴포넌트의 onClick 핸들러 의존성을 재검토할 필요
src/components/Mypage/MenuButton.tsx (1)

7-7: 사용하지 않는 prop을 제거하거나 구현을 완료하세요.

textColor prop이 인터페이스에 선언되어 있지만 컴포넌트 내에서 실제로 사용되지 않습니다. 이 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와 동일합니다.

DeletedContainerReply.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 인터페이스에서 hasImage boolean을 정의했지만, 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 값의 매직 넘버를 명확히 해주세요.

BorderBottomwidth: 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 컴포넌트에 isRecommend prop이 정의되어 있지만 실제로는 사용되지 않습니다. 향후 사용 계획이 없다면 제거하는 것이 타입 정의를 간결하게 유지하는 데 도움이 됩니다.

🔎 개선 제안
-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: 간단한 여백용 div
  • AsideDecoration.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 컴포넌트 추출을 고려하세요.

CarouselContainerNavButtonsrc/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 || undefineddeadlineDate가 이미 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.

📥 Commits

Reviewing files that changed from the base of the PR and between e60f9a4 and dae4521.

📒 Files selected for processing (104)
  • src/components/Mypage/MenuButton.styled.ts
  • src/components/Mypage/MenuButton.tsx
  • src/components/common/AsideDecoration.styled.ts
  • src/components/common/AsideDecoration.tsx
  • src/components/common/Blank.styled.ts
  • src/components/common/Blank.tsx
  • src/components/common/Fab.styled.ts
  • src/components/common/Fab.tsx
  • src/components/common/Filter.styled.ts
  • src/components/common/Filter.tsx
  • src/components/common/IconButton.styled.ts
  • src/components/common/IconButton.tsx
  • src/components/common/LoadingSpinner.styled.ts
  • src/components/common/LoadingSpinner.tsx
  • src/components/common/MainHeader.styled.ts
  • src/components/common/MainHeader.tsx
  • src/components/common/Modal/ConfirmModal.styled.ts
  • src/components/common/Modal/ConfirmModal.tsx
  • src/components/common/Modal/CountingBar.styled.ts
  • src/components/common/Modal/CountingBar.tsx
  • src/components/common/Modal/ImageViewer.styled.ts
  • src/components/common/Modal/ImageViewer.tsx
  • src/components/common/Modal/MoreMenu.styled.ts
  • src/components/common/Modal/MoreMenu.tsx
  • src/components/common/Modal/PopupContainer.styled.ts
  • src/components/common/Modal/PopupContainer.tsx
  • src/components/common/Modal/ReplyModal.styled.ts
  • src/components/common/Modal/ReplyModal.tsx
  • src/components/common/Modal/Snackbar.styled.ts
  • src/components/common/Modal/Snackbar.tsx
  • src/components/common/NavBar.styled.ts
  • src/components/common/NavBar.tsx
  • src/components/common/Post/PostBody.styled.ts
  • src/components/common/Post/PostBody.tsx
  • src/components/common/Post/PostFooter.styled.ts
  • src/components/common/Post/PostFooter.tsx
  • src/components/common/Post/PostHeader.styled.ts
  • src/components/common/Post/PostHeader.tsx
  • src/components/common/Post/Reply.styled.ts
  • src/components/common/Post/Reply.tsx
  • src/components/common/Post/ReplyList.styled.ts
  • src/components/common/Post/ReplyList.tsx
  • src/components/common/Post/SubReply.styled.ts
  • src/components/common/Post/SubReply.tsx
  • src/components/common/TitleHeader.styled.ts
  • src/components/common/TitleHeader.tsx
  • src/components/common/TokenStatus.styled.ts
  • src/components/common/TokenStatus.tsx
  • src/components/common/Wrapper.styled.ts
  • src/components/common/Wrapper.tsx
  • src/components/feed/BookInfoCard.styled.ts
  • src/components/feed/BookInfoCard.tsx
  • src/components/feed/FeedDetailPost.styled.ts
  • src/components/feed/FeedDetailPost.tsx
  • src/components/feed/FeedDetailPostBody.styled.ts
  • src/components/feed/FeedDetailPostBody.tsx
  • src/components/feed/FeedPost.styled.ts
  • src/components/feed/FeedPost.tsx
  • src/components/feed/FollowList.styled.ts
  • src/components/feed/FollowList.tsx
  • src/components/feed/MyFeed.styled.ts
  • src/components/feed/MyFeed.tsx
  • src/components/feed/MyFollower.styled.ts
  • src/components/feed/MyFollower.tsx
  • src/components/feed/OtherFeed.styled.ts
  • src/components/feed/OtherFeed.tsx
  • src/components/feed/Profile.styled.ts
  • src/components/feed/Profile.tsx
  • src/components/feed/TabBar.styled.ts
  • src/components/feed/TabBar.tsx
  • src/components/feed/TotalBar.styled.ts
  • src/components/feed/TotalBar.tsx
  • src/components/feed/TotalFeed.styled.ts
  • src/components/feed/TotalFeed.tsx
  • src/components/feed/UserProfileItem.styled.ts
  • src/components/feed/UserProfileItem.tsx
  • src/components/group/GroupCard.styled.ts
  • src/components/group/GroupCard.tsx
  • src/components/group/MyGroupBox.styled.ts
  • src/components/group/MyGroupBox.tsx
  • src/components/group/MyGroupCard.styled.ts
  • src/components/group/MyGroupCard.tsx
  • src/components/group/MyGroupModal.styled.ts
  • src/components/group/MyGroupModal.tsx
  • src/components/group/PasswordModal.styled.ts
  • src/components/group/PasswordModal.tsx
  • src/components/group/RecruitingGroupBox.styled.ts
  • src/components/group/RecruitingGroupBox.tsx
  • src/components/group/RecruitingGroupCarousel.styled.ts
  • src/components/group/RecruitingGroupCarousel.tsx
  • src/components/memory/UploadProgressBar/UploadProgressBar.styled.ts
  • src/components/memory/UploadProgressBar/UploadProgressBar.tsx
  • src/components/search/BookSearchResult.styled.ts
  • src/components/search/BookSearchResult.tsx
  • src/components/search/GroupSearchResult.styled.ts
  • src/components/search/GroupSearchResult.tsx
  • src/components/search/IntroModal.styled.ts
  • src/components/search/IntroModal.tsx
  • src/components/search/MostSearchedBooks.styled.ts
  • src/components/search/MostSearchedBooks.tsx
  • src/components/search/RecentSearchTabs.styled.ts
  • src/components/search/RecentSearchTabs.tsx
  • src/components/search/SearchBar.styled.ts
  • src/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);
Copy link

Choose a reason for hiding this comment

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

🛠️ 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.

Comment on lines +28 to +29
align-items: flex-start;
align-items: center;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

중복된 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.

Suggested change
align-items: flex-start;
align-items: center;
pointer-events: none;
display: flex;
align-items: center;
min-width: 320px;
Suggested change
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).

Comment on lines +7 to +25
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);
`;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

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.

Suggested change
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.

Comment on lines +16 to +29
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;
`;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 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 -100

Repository: 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 -100

Repository: 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_modules

Repository: 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 -100

Repository: 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 -150

Repository: 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.ts

Repository: 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 {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

::-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.

Suggested change
.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.

Comment on lines +34 to +42
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;
`;
Copy link

Choose a reason for hiding this comment

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

🛠️ 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.

Suggested change
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.

Comment on lines +13 to +23
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%
)
);
Copy link

Choose a reason for hiding this comment

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

🛠️ 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.

Suggested change
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.

Comment on lines +26 to +32
export const Title = styled.h2`
color: #fff;
font-size: ${typography.fontSize.lg};
font-weight: ${typography.fontWeight.bold};
margin-bottom: 32px;
text-align: center;
`;
Copy link

Choose a reason for hiding this comment

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

🛠️ 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.

Comment on lines +4 to +16
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;
`;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

중복된 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.

Suggested change
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.

Comment on lines +15 to +23
.delete-btn {
opacity: 0;
pointer-events: none;
transition: opacity 0.2s;
}
&:focus-within .delete-btn {
opacity: 1;
pointer-events: auto;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

사용되지 않는 .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.

Suggested change
.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.

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: 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초)

문제점:

  1. variant='bottom'의 경우: PopupContainer가 5초에 닫지만 Snackbar는 7초를 기대 → fade-out 애니메이션이 중간에 끊김
  2. 두 타이머가 같은 close 함수를 호출하는 race condition
  3. PR 목표에서 "동작 변화 없음"이라고 했으나, 이 타이밍 로직이 새로 추가된 것이라면 동작이 변경됨

권장 사항:
타이밍 제어를 한 곳에서만 수행하도록 통합해야 합니다. 두 가지 옵션이 있습니다:

  1. PopupContainer의 5초 타이머를 제거하고 Snackbar가 자체적으로 닫도록 함
  2. 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.

📥 Commits

Reviewing files that changed from the base of the PR and between dae4521 and c2e3b6b.

📒 Files selected for processing (8)
  • src/components/common/MainHeader.tsx
  • src/components/common/Modal/ConfirmModal.tsx
  • src/components/common/Modal/MoreMenu.tsx
  • src/components/common/Modal/PopupContainer.tsx
  • src/components/common/Modal/ReplyModal.tsx
  • src/components/common/Modal/Snackbar.tsx
  • src/components/feed/Profile.tsx
  • src/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 파일이 존재하고 ContainerUserProfile을 올바르게 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';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

오타 수정 필요: "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.

@ljh130334 ljh130334 merged commit b1e6076 into THIP-394 Jan 4, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants