[feature] 카테고리 버튼을 리디자인하고 선택 효과를 적용한다#751
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| Cohort / File(s) | Summary |
|---|---|
스타일 변경frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.styles.ts |
컨테이너 마진 축소(60px→32px) 및 모바일 마진 단순화; 버튼 패딩 변경(8px→8px 0); 아이콘 데스크탑 기본 크기 확대(36→56) 및 뷰포트별 축소 규칙 추가; 캡션 폰트 크기/색(#787878)/간격 및 반응형 조정. |
아이콘 자원 및 매핑 추가frontend/src/assets/images/icons/category_button/index.ts |
inactive/active 상태별 SVG 임포트 및 inactiveCategoryIcons / activeCategoryIcons 레코드 매핑 추가(카테고리 키 → 경로). |
렌더링 로직 변경frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.tsx |
개별 아이콘 임포트 제거 후 매핑 사용으로 교체. Category에서 icon 제거·type 사용. zustand의 useSelectedCategory에서 selectedCategory를 읽어 현재 선택 항목이면 activeCategoryIcons[category.type] 사용, 아니면 inactiveCategoryIcons[category.type] 사용하도록 변경. 클릭 핸들링(트래킹/검색 리셋/setSelectedCategory)은 유지. |
스토어 셀렉터 포맷 변경frontend/src/store/useCategoryStore.ts |
setSelectedCategory 셀렉터를 한 줄로 리팩터링(기능적 변경 없음). |
상수 매핑 교체frontend/src/constants/CLUB_UNION_INFO.ts |
개별 아바타 임포트 제거, inactiveCategoryIcons를 사용해 MEMBER_AVATARS 매핑을 재지정(이미지 경로 참조만 변경). |
Sequence Diagram(s)
sequenceDiagram
actor U as 사용자
participant CBL as CategoryButtonList
participant Icons as Icon Mapping Module
participant Store as useSelectedCategory (zustand)
participant Analytics as Analytics
participant Search as SearchStore
U->>CBL: 카테고리 버튼 클릭
CBL->>Analytics: 클릭 이벤트 전송
CBL->>Search: 검색 상태 초기화
CBL->>Store: setSelectedCategory(category.type)
Store-->>CBL: selectedCategory 갱신 알림
CBL->>Icons: 요청(카테고리.type, selectedCategory)
Icons-->>CBL: active or inactive icon path
CBL-->>U: UI 갱신(아이콘: active/inactive)
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related issues
- [feature] MOA-235 카테고리 버튼을 리디자인하고 선택 효과를 적용한다 #743: 카테고리 버튼 리디자인 및 선택 효과 적용 목표와 직접적으로 일치하므로 연결 가능.
Possibly related PRs
- [refactor] 카테고리 context를 zustand기반으로 마이그레이션 #729: zustand 기반 카테고리 상태 접근 관련 변경과 강한 연관성 있음.
- [refactor] 카테고리 버튼 클릭 로깅 통일 #638: Category 구조(타입/데이터) 및 CategoryButtonList 조정과 코드 레벨 연관성 큼.
- [feature] 카테고리 선택 상태 Context 전역 관리로 변경 및 페이지 이동 시 상태 유지 #512: 전역 선택 상태 접근 방식 변경 관련 변경과 연관 있음.
Suggested reviewers
- lepitaaar
- oesnuj
- Zepelown
Pre-merge checks and finishing touches
✅ Passed checks (5 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title Check | ✅ Passed | 제목 "[feature] 카테고리 버튼을 리디자인하고 선택 효과를 적용한다"는 PR의 핵심 변경사항인 카테고리 버튼의 디자인 변경 및 선택 상태 적용을 명확하고 간결하게 요약하고 있어, 변경 내용과 직접적으로 일치합니다. |
| Linked Issues Check | ✅ Passed | PR은 카테고리 버튼 리디자인(스타일 조정: frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.styles.ts)과 선택 효과(활성/비활성 아이콘 매핑 및 선택 상태 반영: frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.tsx, 새 아이콘 매핑 frontend/src/assets/images/icons/category_button/index.ts)를 구현하고 있으며, linked issue MOA-235의 체크리스트 항목들을 충족합니다; 공개 API 변경은 없습니다. |
| Out of Scope Changes Check | ✅ Passed | 변경 내용은 주로 카테고리 버튼 관련 스타일·아이콘 중앙화 및 렌더링 로직에 국한되며, CLUB_UNION_INFO.ts에서 아이콘 소스를 inactiveCategoryIcons로 전환한 것은 자산 리팩터링에 해당하므로 요구사항 범위에서 벗어난 큰 기능 변경으로 보이지 않습니다. |
| Docstring Coverage | ✅ Passed | No functions found in the changes. Docstring coverage check skipped. |
✨ Finishing touches
- 📝 Generate Docstrings
🧪 Generate unit tests
- Create PR with unit tests
- Post copyable unit tests in a comment
- Commit unit tests in branch
feature/#743-update-category-button-MOA-235
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 @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (5)
frontend/src/store/useCategoryStore.ts (1)
29-31: zustand 구독 2회 → 1회로 축소(shallow 비교 권장)동일 훅을 두 번 호출해 두 개의 구독이 생깁니다. 미미하지만 하나의 셀렉터로 묶고 shallow 비교를 적용하면 불필요한 리렌더를 줄일 수 있습니다.
적용 diff:
- const selectedCategory = useCategoryStore((state) => state.selectedCategory); - const setSelectedCategory = useCategoryStore((state) => state.setSelectedCategory); - return { selectedCategory, setSelectedCategory }; + const { selectedCategory, setSelectedCategory } = useCategoryStore( + (state) => ({ selectedCategory: state.selectedCategory, setSelectedCategory: state.setSelectedCategory }), + shallow, + ); + return { selectedCategory, setSelectedCategory };추가(파일 상단 임포트):
import { shallow } from 'zustand/shallow';frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.tsx (2)
21-26: 카테고리 id를 유니온 타입으로 고정하여 오타/런타임 오류 예방id를 문자열 유니온으로 제한하면 선택/비교 로직의 안정성이 올라갑니다(오타로 인한 미매칭 방지).
적용 diff:
-interface Category { - id: string; - name: string; - icon: string; - activeIcon: string -} +type CategoryId = 'all' | '봉사' | '종교' | '취미교양' | '학술' | '운동' | '공연'; + +interface Category { + id: CategoryId; + name: string; + icon: string; + activeIcon: string; +}
57-63: button 기본 type 지정 및 접근성 상태 노출(aria-pressed) 추가
- 기본 type 미지정 시 폼 내부에서 의도치 않게 submit 됩니다.
- 선택 상태를 스크린리더에 노출하면 접근성이 개선됩니다.
적용 diff:
- <Styled.CategoryButton + <Styled.CategoryButton key={category.id} - onClick={() => handleCategoryClick(category)} + onClick={() => handleCategoryClick(category)} + type="button" + aria-pressed={selectedCategory === category.id} > - <img src={selectedCategory === category.id ? category.activeIcon : category.icon} alt={category.name} /> + <img + src={selectedCategory === category.id ? category.activeIcon : category.icon} + alt={category.name} + loading="lazy" + /> <span>{category.name}</span> </Styled.CategoryButton>추가로, 가독성을 위해 조건을 변수로 뽑는 것도 고려해 주세요(가이드라인: 복합 불린을 명명된 변수로). 예: const isSelected = selectedCategory === category.id.
frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.styles.ts (2)
7-7: 여러 magic number를 상수/토큰으로 치환여러 px 값과 색상이 하드코딩되어 있습니다. 상수 또는 디자인 토큰(theme)으로 연결하면 유지보수성과 일관성이 좋아집니다.
적용 diff(치환 예):
- margin-top: 32px; + margin-top: ${MARGIN_TOP_DESKTOP}px; @@ - margin: 16px 0 12px 0; + margin: ${MARGIN_TOP_MOBILE}px 0 ${MARGIN_BOTTOM_MOBILE}px 0; @@ - padding: 8px 0px; + padding: ${BUTTON_PADDING_Y}px 0; @@ - width: 56px; - height: 56px; + width: ${ICON_SIZE_DESKTOP}px; + height: ${ICON_SIZE_DESKTOP}px; @@ - width: 40px; - height: 40px; + width: ${ICON_SIZE_SM}px; + height: ${ICON_SIZE_SM}px; @@ - width: 23px; - height: 23px; + width: ${ICON_SIZE_XS}px; + height: ${ICON_SIZE_XS}px; @@ - font-size: 14px; + font-size: ${FONT_SIZE_BASE}px; @@ - color: #787878; - margin-top: 8px; + color: ${TEXT_COLOR_SECONDARY}; + margin-top: ${LABEL_MARGIN_TOP_BASE}px; @@ - font-size: 12px; + font-size: ${FONT_SIZE_SM}px; @@ - font-size: 10px; - margin-top: 4px; + font-size: ${FONT_SIZE_XS}px; + margin-top: ${LABEL_MARGIN_TOP_SM}px; @@ - font-size: 8px; + font-size: ${FONT_SIZE_XXS}px;상수 선언(파일 상단에 추가):
const MARGIN_TOP_DESKTOP = 32; const MARGIN_TOP_MOBILE = 16; const MARGIN_BOTTOM_MOBILE = 12; const BUTTON_PADDING_Y = 8; const ICON_SIZE_DESKTOP = 56; const ICON_SIZE_SM = 40; const ICON_SIZE_XS = 23; const FONT_SIZE_BASE = 14; const FONT_SIZE_SM = 12; const FONT_SIZE_XS = 10; const FONT_SIZE_XXS = 10; // 가독성 확보를 위해 8 → 10 권장 const LABEL_MARGIN_TOP_BASE = 8; const LABEL_MARGIN_TOP_SM = 4; const TEXT_COLOR_SECONDARY = '#787878'; // 가능하면 theme.colors.textSecondary 사용Also applies to: 10-10, 25-25, 33-34, 38-39, 42-43, 48-48, 50-51, 56-56, 61-62, 67-67
10-10: 스크롤바 토글로 인한 배너 레이아웃 흔들림 완화 제안보고된 현상은 수직 스크롤바 생성/제거 시 뷰포트 폭이 변해 발생할 수 있습니다. 전역 스타일에 scrollbar-gutter: stable both-edges를 적용해 레이아웃 변동을 줄여보세요(지원 브라우저에서 유효).
전역 스타일 예(별도 파일):
// GlobalStyle.ts export const GlobalStyle = createGlobalStyle` html { scrollbar-gutter: stable both-edges; } /* 대안: 항상 스크롤바 확보 */ /* html { overflow-y: scroll; } */ `;배너/헤더와의 z-index, sticky(top: 56px) 충돌 여부도 함께 점검 바랍니다.
📜 Review details
Configuration used: CodeRabbit 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 ignored due to path filters (14)
frontend/src/assets/images/icons/category_button/category_all_button_icon.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_all_button_icon_active.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_hobby_button_icon.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_hobby_button_icon_active.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_performance_button_icon.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_performance_button_icon_active.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_religion_button_icon.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_religion_button_icon_active.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_sport_button_icon.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_sport_button_icon_active.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_study_button_icon.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_study_button_icon_active.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_volunteer_button_icon.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_volunteer_button_icon_active.svgis excluded by!**/*.svg
📒 Files selected for processing (3)
frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.styles.ts(2 hunks)frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.tsx(3 hunks)frontend/src/store/useCategoryStore.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.{ts,tsx}: Replace magic numbers with named constants for clarity.
Replace complex or nested ternary operators with if/else statements or IIFEs for readability.
Assign complex boolean conditions to named variables.
Use consistent return types for similar functions and hooks.
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle).
Use unique, descriptive names for custom wrappers and functions to avoid ambiguity.
Define constants near related logic or ensure names link them clearly.
Files:
frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.tsxfrontend/src/store/useCategoryStore.tsfrontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.styles.ts
frontend/**/*.tsx
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.tsx: Abstract complex logic/interactions into dedicated components or higher-order components (HOCs).
Separate significantly different conditional UI/logic into distinct components.
Colocate simple, localized logic or use inline definitions to reduce context switching.
Choose field-level or form-level cohesion based on form requirements.
Break down broad state management into smaller, focused hooks or contexts.
Use component composition instead of props drilling.
Files:
frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.tsx
🧬 Code graph analysis (1)
frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.tsx (1)
frontend/src/store/useCategoryStore.ts (1)
useSelectedCategory(28-32)
🔇 Additional comments (1)
frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.tsx (1)
10-16: active 아이콘 도입 LGTM — 자산 누락 없음 (검증 완료)frontend/src/assets/images/icons/category_button 내 category_*_button_icon_active.svg 7/7 파일 존재 확인.
frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.styles.ts
Outdated
Show resolved
Hide resolved
| import iconAllActive from '@/assets/images/icons/category_button/category_all_button_icon_active.svg'; | ||
| import iconVolunteerActive from '@/assets/images/icons/category_button/category_volunteer_button_icon_active.svg'; | ||
| import iconReligionActive from '@/assets/images/icons/category_button/category_religion_button_icon_active.svg'; | ||
| import iconHobbyActive from '@/assets/images/icons/category_button/category_hobby_button_icon_active.svg'; | ||
| import iconStudyActive from '@/assets/images/icons/category_button/category_study_button_icon_active.svg'; | ||
| import iconSportActive from '@/assets/images/icons/category_button/category_sport_button_icon_active.svg'; | ||
| import iconPerformanceActive from '@/assets/images/icons/category_button/category_performance_button_icon_active.svg'; |
There was a problem hiding this comment.
처음에는 아이콘이 몇 개 안 될 줄 알고 개별 import 했는데
이렇게 14개 정도로 늘어나면 index.ts로 모아서 재export 하는 게 훨씬 깔끔하겠네요
방식은 크게 두 가지가 있어용
1️⃣ 단순 모아주기 방식
카테고리 아이콘들 폴더에 index.ts를 만들고, 각 SVG의 default export를 이름 붙여 다시 export 합니다.
// index.ts
...
export { default as iconAllActive } from './category_all_button_icon_active.svg';
export { default as iconVolunteerActive } from './category_volunteer_button_icon_active.svg';
export { default as iconReligionActive } from './category_religion_button_icon_active.svg';
export { default as iconHobbyActive } from './category_hobby_button_icon_active.svg';
export { default as iconStudyActive } from './category_study_button_icon_active.svg';
export { default as iconSportActive } from './category_sport_button_icon_active.svg';
export { default as iconPerformanceActive } from './category_performance_button_icon_active.svg';→ 사용하는 쪽에서는 한줄로 가능
import {
...
iconAllActive,
iconVolunteerActive,
iconReligionActive,
iconHobbyActive,
iconStudyActive,
iconSportActive,
iconPerformanceActive,
} from '@/assets/images/icons/category_button';2️⃣ 객체(Map)으로 묶기 방식
만약 카테고리별로 매핑이 필요하다면 객체로 관리하는 것도 좋아요.
// index.ts
import all from './category_all_button_icon_active.svg';
import volunteer from './category_volunteer_button_icon_active.svg';
import religion from './category_religion_button_icon_active.svg';
import hobby from './category_hobby_button_icon_active.svg';
import study from './category_study_button_icon_active.svg';
import sport from './category_sport_button_icon_active.svg';
import performance from './category_performance_button_icon_active.svg';
...
export const categoryIcons = {
all,
volunteer,
religion,
hobby,
study,
sport,
performance,
} as const;→ 사용 시에는 이렇게 더 짧게 가능함다, 대신 .으로 내부 접근 필요하죠
import { categoryIcons } from '@/assets/images/icons/category_button';
<img src={categoryIcons.study} alt="스터디 아이콘" />장점
- import 구문이 훨씬 짧아짐 (코드 가독성 ↑)
- 아이콘 추가/삭제 관리가 쉬움 (한 곳에서만 관리)
- (2번 객체 방식일 경우) 카테고리 키 기반 접근 가능 → 반복 코드 줄고 확장성 ↑
- 파일 구조 변경 시 유지보수 용이 (경로가 바뀌어도 index.ts만 수정)
There was a problem hiding this comment.
조언 감사합니다!!!
export const inactiveCategoryIcons : Record<string, string> = {
all : iconAll,
volunteer : iconVolunteer,
religion : iconReligion,
hobby : iconHobby,
study : iconStudy,
sport : iconSport,
performance : iconPerformance
}
export const activeCategoryIcons : Record<string, string> = {
all : iconAllActive,
volunteer : iconVolunteerActive,
religion : iconReligionActive,
hobby : iconHobbyActive,
study : iconStudyActive,
sport : iconSportActive,
performance : iconPerformanceActive
}수정 완료했습니다! import가 많아서 정신없었는데, 깔끔해진 것 같아요~
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
frontend/src/assets/images/icons/category_button/index.ts (2)
16-24: 타입 안전성 강화: Record<string, string> → CategoryType 유니온으로 한정키가 자유로운 string이면 누락/오타가 런타임 undefined로 새어 나올 위험이 있습니다. 카테고리 키를 유니온으로 고정하고 Readonly로 동결해 주세요. 소비자 코드(스토어, 리스트)도 동일 타입을 재사용하면 불일치가 사전에 차단됩니다.
다음과 같이 변경을 제안합니다.
+// 카테고리 키 소스 오브 트루스 +export const CATEGORY_TYPES = ['all','volunteer','religion','hobby','study','sport','performance'] as const; +export type CategoryType = typeof CATEGORY_TYPES[number]; -export const inactiveCategoryIcons : Record<string, string> = { +export const inactiveCategoryIcons: Readonly<Record<CategoryType, string>> = { all : iconAll, volunteer : iconVolunteer, religion : iconReligion, hobby : iconHobby, study : iconStudy, sport : iconSport, performance : iconPerformance }또는 다음과 같이 satisfies를 사용할 수도 있습니다(개인 선호):
export const inactiveCategoryIcons = { all: iconAll, volunteer: iconVolunteer, religion: iconReligion, hobby: iconHobby, study: iconStudy, sport: iconSport, performance: iconPerformance, } satisfies Record<CategoryType, string>;
26-34: 동일한 타입 제약을 active 맵에도 적용active 맵도 동일한 타입 제약을 적용해 키 불일치를 방지하세요.
-export const activeCategoryIcons : Record<string, string> = { +export const activeCategoryIcons: Readonly<Record<CategoryType, string>> = { all : iconAllActive, volunteer : iconVolunteerActive, religion : iconReligionActive, hobby : iconHobbyActive, study : iconStudyActive, sport : iconSportActive, performance : iconPerformanceActive }또한 소비자에서의 분기 단순화를 위해 선택적 헬퍼를 제공할 수 있습니다(선택):
export const getCategoryIcon = (type: CategoryType, isActive: boolean): string => isActive ? activeCategoryIcons[type] : inactiveCategoryIcons[type];
📜 Review details
Configuration used: CodeRabbit 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 (2)
frontend/src/assets/images/icons/category_button/index.ts(1 hunks)frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.tsx(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.tsx
🧰 Additional context used
📓 Path-based instructions (1)
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.{ts,tsx}: Replace magic numbers with named constants for clarity.
Replace complex or nested ternary operators with if/else statements or IIFEs for readability.
Assign complex boolean conditions to named variables.
Use consistent return types for similar functions and hooks.
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle).
Use unique, descriptive names for custom wrappers and functions to avoid ambiguity.
Define constants near related logic or ensure names link them clearly.
Files:
frontend/src/assets/images/icons/category_button/index.ts
🔇 Additional comments (2)
frontend/src/assets/images/icons/category_button/index.ts (2)
16-34: 키 명칭 일치 확인 — 수정 불필요icons 모듈(frontend/src/assets/images/icons/category_button/index.ts)과 사용처(frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.tsx, frontend/src/store/useCategoryStore.ts)에서 모두 'sport' 키로 일치합니다.
1-14: SVG 활성/비활성 페어의 viewBox/크기 일치 여부 확인 필요활성/비활성 아이콘의 viewBox/width/height 불일치로 선택 시 레이아웃 점프가 발생할 수 있습니다 — PR 본문에서 언급된 '종교' 배너 이상과 연관 가능성이 있으니 frontend/src/assets/images/icons/category_button/ 폴더의 SVG 페어를 확인하고 제공한 검사 스크립트를 로컬에서 실행하여 불일치 출력(또는 스크린샷)을 첨부하십시오.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
frontend/src/constants/CLUB_UNION_INFO.ts (2)
12-21: 타입 안전성 강화: as const + satisfies로 키 오타를 컴파일 타임에 차단현재
inactiveCategoryIcons가Record<string, string>라 속성 오타가 컴파일 타임에 검출되지 않습니다. 이 맵은 변경 빈도가 낮으므로 리터럴 고정과 키 유니언을 적용해 안전성을 높이는 걸 권장합니다.아래처럼 키 유니언을 선언하고, 맵에
as const satisfies를 적용해 주세요.@@ -const MEMBER_AVATARS = { +type MemberAvatarKey = + | 'PRESIDENT' + | 'VICE_PRESIDENT' + | 'SECRETARY' + | 'PROMOTION' + | 'RELIGION' + | 'HOBBY' + | 'STUDY' + | 'VOLUNTEER' + | 'PERFORMANCE' + | 'SPORT'; + +const MEMBER_AVATARS = { PRESIDENT: inactiveCategoryIcons.all, VICE_PRESIDENT: inactiveCategoryIcons.all, SECRETARY: inactiveCategoryIcons.all, PROMOTION: inactiveCategoryIcons.all, RELIGION: inactiveCategoryIcons.religion, HOBBY: inactiveCategoryIcons.hobby, STUDY: inactiveCategoryIcons.study, VOLUNTEER: inactiveCategoryIcons.volunteer, PERFORMANCE: inactiveCategoryIcons.performance, SPORT: inactiveCategoryIcons.sport, -}; +} as const satisfies Record<MemberAvatarKey, string>;추가로, 가능하다면 아이콘 모듈(
category_button/index.ts)에서도Record<string,string>대신as const로 키를 고정해keyof를 노출하면 전역적으로 더 안전해집니다.
12-21: 배너 흔들림 이슈 대응안(참고): 스크롤바 토글로 인한 레이아웃 시프트 방지PR 설명의 배너 레이아웃 깨짐은 스크롤바 등장/제거에 따른 컨테이너 폭 변화일 가능성이 큽니다. 카테고리 선택과 맞물려 발생한다면, 컨테이너에 아래 CSS를 고려해 주세요.
.container { /* 스크롤바 유무와 관계없이 공간 예약 */ scrollbar-gutter: stable both-edges; } /* 광범위 호환성 보완책 */ @supports not (scrollbar-gutter: stable) { .container { overflow-y: scroll; } /* 항상 세로 스크롤 공간 확보 */ }의도된 레이아웃 컨테이너에 적용 후, 문제 재현 케이스(종교 카테고리 선택)에서 시프트가 사라지는지 확인 부탁드립니다.
📜 Review details
Configuration used: CodeRabbit 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 (1)
frontend/src/constants/CLUB_UNION_INFO.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.{ts,tsx}: Replace magic numbers with named constants for clarity.
Replace complex or nested ternary operators with if/else statements or IIFEs for readability.
Assign complex boolean conditions to named variables.
Use consistent return types for similar functions and hooks.
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle).
Use unique, descriptive names for custom wrappers and functions to avoid ambiguity.
Define constants near related logic or ensure names link them clearly.
Files:
frontend/src/constants/CLUB_UNION_INFO.ts
🧬 Code graph analysis (1)
frontend/src/constants/CLUB_UNION_INFO.ts (1)
frontend/src/assets/images/icons/category_button/index.ts (1)
inactiveCategoryIcons(16-24)
🔇 Additional comments (2)
frontend/src/constants/CLUB_UNION_INFO.ts (2)
12-21: 디자인 의도 확인: 임원 4개 항목이 모두 all 아이콘 사용
PRESIDENT/VICE_PRESIDENT/SECRETARY/PROMOTION이 동일하게all아이콘을 쓰는 것이 최종 디자인 의도인지 확인 부탁드립니다. 역할별 별도 아바타가 필요 없다면 현재 구현으로 충분합니다.
1-1: 중앙화된 아이콘 모듈 import 적절 — 경로 별칭(@) 확인 필요 (자동검증 불가)배럴에서의 명시적 import는 적절합니다. 자동 검증 중 frontend/tsconfig.json이 유효한 JSON이 아니라 '@' → 'src' 매핑 확인과 inactiveCategoryIcons export 검사에 실패했습니다. 아래를 확인해 재검증해 주세요.
위치:
- frontend/tsconfig.json
- frontend/src/assets/images/icons/category_button/index.ts
로컬에서 실행할 검증 명령:
python3 -m json.tool frontend/tsconfig.json rg -n -C2 "inactiveCategoryIcons" frontend/src || true rg -n -C2 -P "export\s+(const|default)\s+inactiveCategoryIcons" frontend/src || true ls -la frontend/src/assets/images/icons/category_button || true

#️⃣연관된 이슈
📝작업 내용
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit