-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feat] 주제 설정 페이지 퍼블리싱 및 폼 연동 #95
Conversation
…m-1-FE into feat/#7185da535
Warning There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure. 🔧 ESLint
apps/web/src/app/create/Create.tsxOops! Something went wrong! :( ESLint: 9.17.0 Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@repo/eslint-config' imported from /eslint.config.mjs Walkthrough이 풀 리퀘스트는 웹 애플리케이션의 주제 설정 페이지를 위한 새로운 컴포넌트와 기능을 추가합니다. 주요 변경 사항은 Changes
Assessment against linked issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🧹 Nitpick comments (17)
apps/web/src/app/create/_components/KeywordChip/KeywordChip.css.ts (1)
18-18
: 트랜지션 속성을 구체화하는 것이 좋습니다.현재 'all' 트랜지션은 불필요한 속성들에도 적용될 수 있습니다. 필요한 속성만 명시하는 것이 성능상 좋습니다.
- transition: 'all 0.2s ease', + transition: 'background-color 0.2s ease, color 0.2s ease, opacity 0.2s ease',apps/web/src/app/create/_components/KeywordChip/KeywordChip.tsx (2)
33-42
: useEffect 클린업 함수의 안정성을 개선할 수 있습니다.itemsRef 배열을 직접 수정하는 방식은 잠재적인 동시성 문제를 일으킬 수 있습니다.
useEffect(() => { const currentRef = itemRef.current; if (currentRef) { - itemsRef.push(currentRef); + const newItemsRef = [...itemsRef, currentRef]; + itemsRef.length = 0; + itemsRef.push(...newItemsRef); return () => { - const index = itemsRef.indexOf(currentRef); - if (index !== -1) itemsRef.splice(index, 1); + const newItemsRef = itemsRef.filter(ref => ref !== currentRef); + itemsRef.length = 0; + itemsRef.push(...newItemsRef); }; } }, [itemsRef]);
60-63
: non-null assertion 연산자 사용을 피하는 것이 좋습니다.
itemRef.current!
에서 non-null assertion 연산자를 사용하는 것보다 안전한 방법을 사용하는 것이 좋습니다.- const currentIndex = itemsRef.indexOf(itemRef.current!); + const currentRef = itemRef.current; + const currentIndex = currentRef ? itemsRef.indexOf(currentRef) : -1; + if (currentIndex === -1) return; onKeyDown?.(e, currentIndex);apps/web/src/app/create/_components/KeywordChip/KeywordChipGroup.tsx (2)
13-19
: Props 타입 정의를 개선할 수 있습니다.children의 타입이 너무 광범위하게 정의되어 있습니다. 더 구체적인 타입을 사용하면 좋을 것 같습니다.
type KeywordChipGroupProps = { - children: ReactNode[]; + children: (string | number)[]; onChange?: (value: string) => void; defaultValue?: string; disabled?: boolean; name?: string; };
84-86
: 타입 안전성을 개선할 수 있습니다.
child?.toString()
의 사용이 잠재적으로 안전하지 않을 수 있습니다. 더 명시적인 타입 체크를 추가하는 것이 좋습니다.- <KeywordChip key={child?.toString()} value={child?.toString() ?? ''}> + <KeywordChip + key={String(child)} + value={String(child)} + > {child} </KeywordChip>packages/theme/src/themes/light.ts (1)
Line range hint
39-43
: 컬러 토큰 추가가 잘 되었습니다.
primary200
토큰이 기존 primary 컬러 스케일에 잘 통합되었습니다. 다만, 컬러 시스템의 유지보수성을 위해 다음을 제안드립니다:
- 컬러 토큰들을 시각적으로 그룹화하여 주석으로 구분
- 각 primary 컬러의 사용 목적을 문서화
+ // Primary colors - Main brand colors + // primary200: Buttons, Links + // primary500: Primary actions + // primary600: Hover states + // primary700: Active states + // primary800: Special emphasis primary200: tokens.colors.primary200, primary500: tokens.colors.primary500, primary600: tokens.colors.primary600, primary700: tokens.colors.primary700, primary800: tokens.colors.primary800,apps/web/src/utils/isEmptyStringOrNil.ts (1)
3-7
: 타입 안전성과 유효성 검사를 개선할 수 있습니다.현재 구현은 작동하지만, 다음과 같은 개선사항을 고려해보세요:
- 타입을 더 구체적으로 정의
- 입력값 검증 강화
다음과 같이 개선할 수 있습니다:
-type NullableString = string | null | undefined; +type NullableString = string | null | undefined; +type EmptyCheckResult = boolean; -export function isEmptyStringOrNil(value: NullableString): boolean { +export function isEmptyStringOrNil(value: NullableString): EmptyCheckResult { + if (typeof value === 'string') { + return value.trim() === ''; + } return isNil(value) || value.trim() === ''; }apps/web/src/components/common/MainBreadcrumbItem/MainBreadcrumbItem.tsx (1)
5-7
: Props 타입 정의를 개선할 수 있습니다.타입 정의에 다음과 같은 개선사항을 추가하면 좋을 것 같습니다:
- 문서화를 위한 JSDoc 주석 추가
- 필수 속성과 선택적 속성 구분
+/** + * 메인 브레드크럼 아이템 컴포넌트의 속성 + * @property {string} [href] - 네비게이션 링크 주소 (기본값: '/create') + */ type MainBreadcrumbItemProps = { href?: string; };apps/web/src/app/create/_components/AnimatedContainer/AnimatedContainer.tsx (1)
13-19
: 애니메이션 값을 상수로 분리하는 것이 좋겠습니다.애니메이션 관련 값들을 상수로 분리하여 재사용성과 유지보수성을 높일 수 있습니다.
다음과 같이 상수를 분리하는 것을 제안합니다:
+const ANIMATION_CONFIG = { + initial: { y: '100%' }, + animate: { y: 0 }, + transition: { + type: 'spring', + duration: 0.6, + bounce: 0.22, + }, +} as const; export function AnimatedContainer({ children }: AnimatedContainerProps) { return ( <motion.div className={styles.containerStyle} - initial={{ y: '100%' }} - animate={{ y: 0 }} - transition={{ - type: 'spring', - duration: 0.6, - bounce: 0.22, - }} + {...ANIMATION_CONFIG} >apps/web/src/components/common/MainBreadcrumbItem/MainBreadcrumbItem.css.ts (1)
4-14
: z-index 값을 상수로 분리하는 것이 좋겠습니다.z-index 값을 의미 있는 이름을 가진 상수로 분리하면 다른 컴포넌트와의 레이어 관계를 더 명확하게 관리할 수 있습니다.
다음과 같이 상수를 분리하는 것을 제안합니다:
+const Z_INDICES = { + HEADER: 1000, +} as const; export const headerStyle = style({ display: 'flex', justifyContent: 'space-between', alignItems: 'center', position: 'fixed', top: 0, left: 0, right: 0, padding: `${vars.space[12]} ${vars.space[24]}`, - zIndex: 1000, + zIndex: Z_INDICES.HEADER, });apps/web/src/app/create/_components/GradientAnimatedTitle/GradientAnimatedTitle.css.ts (2)
4-11
: 애니메이션 성능 최적화가 필요합니다.애니메이션이 부드럽게 동작하도록
backgroundPosition
값을 최적화하는 것이 좋습니다. 현재 구현은 CPU 사용량이 높을 수 있습니다.const flowingGradient = keyframes({ '0%': { backgroundPosition: '0% 50%', }, + '50%': { + backgroundPosition: '100% 50%', + }, '100%': { - backgroundPosition: '200% 50%', + backgroundPosition: '0% 50%', }, });
13-24
: 그라데이션 색상을 테마 변수로 관리하는 것이 좋습니다.현재 하드코딩된 색상 값들을 테마 변수로 이동하여 일관성 있게 관리하면 좋을 것 같습니다.
+// theme.ts에 추가 +export const gradientColors = { + primary: '#1F3761', + secondary: '#2646C5', + tertiary: '#615BE7', +}; export const gradientTitleStyle = style({ background: - 'linear-gradient(90deg, #1F3761 0%, #2646C5 10%, #615BE7 30%, #615BE7 70%, #2646C5 93%, #1F3761 97%, #1F3761 100%)', + `linear-gradient(90deg, ${vars.gradientColors.primary} 0%, ${vars.gradientColors.secondary} 10%, ${vars.gradientColors.tertiary} 30%, ${vars.gradientColors.tertiary} 70%, ${vars.gradientColors.secondary} 93%, ${vars.gradientColors.primary} 97%, ${vars.gradientColors.primary} 100%)`, // ... rest of the styles });apps/web/src/app/create/_components/GradientAnimatedTitle/GradientAnimatedTitle.tsx (1)
15-21
: 애니메이션 값을 상수로 분리하는 것이 좋습니다.애니메이션의 initial과 animate 값을 상수로 분리하여 코드의 가독성과 재사용성을 높이면 좋을 것 같습니다.
+const INITIAL_ANIMATION = { + y: '35vh', + scale: 2, + x: '-50%', + left: '50%', + position: 'absolute', +} as const; + +const ANIMATE_VALUES = { + y: 0, + scale: 1, + x: 0, + left: 'auto', + position: 'relative', +} as const; export function GradientAnimatedTitle({ children, }: GradientAnimatedTitleProps) { return ( <motion.h1 className={styles.gradientTitleStyle} - initial={{ - y: '35vh', - scale: 2, - x: '-50%', - left: '50%', - position: 'absolute', - }} - animate={{ - y: 0, - scale: 1, - x: 0, - left: 'auto', - position: 'relative', - }} + initial={INITIAL_ANIMATION} + animate={ANIMATE_VALUES}Also applies to: 22-28
apps/web/src/app/create/pageStyle.css.ts (2)
21-21
: z-index 값을 테마 변수로 관리하는 것이 좋습니다.z-index 값을 테마 변수로 이동하여 일관성 있게 관리하면 좋을 것 같습니다.
+// theme.ts에 추가 +export const zIndices = { + header: 1000, + modal: 2000, + tooltip: 3000, +} as const; export const headerStyle = style({ // ... other styles - zIndex: 1000, + zIndex: vars.zIndices.header, });
27-27
: gap 값을 테마 변수로 관리하는 것이 좋습니다.하드코딩된 gap 값을 테마의 space 변수를 사용하도록 변경하면 좋을 것 같습니다.
export const contentStyle = style({ display: 'flex', flexDirection: 'column', - gap: '4.8rem', + gap: vars.space[48], });apps/web/src/app/create/constants.ts (2)
1-18
: 타입 상수에 JSDoc 문서화 추가 필요각 타입 상수(
PURPOSE_TYPE
,REFERENCE_TYPE
,LENGTH_TYPE
)에 대한 설명과 사용 목적을 명시하는 JSDoc 문서화가 필요합니다.+/** + * 글 작성 목적을 정의하는 상수 + * @type {Object} + */ export const PURPOSE_TYPE = { INFORMATION: 'INFORMATION', OPINION: 'OPINION', HUMOR: 'HUMOR', MARKETING: 'MARKETING', } as const;
64-83
: 길이 옵션의 문자 제한을 상수로 분리 필요
LENGTH_OPTIONS
에 하드코딩된 문자 제한(140자
,300자
,1000자
)을 별도의 상수로 분리하여 관리하면 좋을 것 같습니다.+export const LENGTH_LIMITS = { + SHORT: 140, + MEDIUM: 300, + LONG: 1000, +} as const; export const LENGTH_OPTIONS = [ { value: LENGTH_TYPE.SHORT, label: '짧은 게시물', - description: '약 1~2문장, 최대 140자', + description: `약 1~2문장, 최대 ${LENGTH_LIMITS.SHORT}자`, badge: '누구나 이용 가능', }, // ... 나머지 옵션들도 동일하게 수정 ] as const;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (31)
apps/web/package.json
(1 hunks)apps/web/src/app/create/Create.tsx
(1 hunks)apps/web/src/app/create/_components/AnimatedContainer/AnimatedContainer.css.ts
(1 hunks)apps/web/src/app/create/_components/AnimatedContainer/AnimatedContainer.tsx
(1 hunks)apps/web/src/app/create/_components/GradientAnimatedTitle/GradientAnimatedTitle.css.ts
(1 hunks)apps/web/src/app/create/_components/GradientAnimatedTitle/GradientAnimatedTitle.tsx
(1 hunks)apps/web/src/app/create/_components/KeywordChip/KeywordChip.css.ts
(1 hunks)apps/web/src/app/create/_components/KeywordChip/KeywordChip.tsx
(1 hunks)apps/web/src/app/create/_components/KeywordChip/KeywordChipGroup.tsx
(1 hunks)apps/web/src/app/create/_components/KeywordChip/context.tsx
(1 hunks)apps/web/src/app/create/constants.ts
(1 hunks)apps/web/src/app/create/page.tsx
(1 hunks)apps/web/src/app/create/pageStyle.css.ts
(1 hunks)apps/web/src/app/create/types.ts
(1 hunks)apps/web/src/app/page.tsx
(1 hunks)apps/web/src/components/common/ImageManager/TypeA/TypeA.css.ts
(1 hunks)apps/web/src/components/common/ImageManager/TypeA/TypeA.tsx
(3 hunks)apps/web/src/components/common/ImageManager/TypeA/UploadedImages.css.ts
(1 hunks)apps/web/src/components/common/ImageManager/index.ts
(0 hunks)apps/web/src/components/common/MainBreadcrumbItem/MainBreadcrumbItem.css.ts
(1 hunks)apps/web/src/components/common/MainBreadcrumbItem/MainBreadcrumbItem.tsx
(1 hunks)apps/web/src/components/common/index.ts
(1 hunks)apps/web/src/utils/index.ts
(1 hunks)apps/web/src/utils/isEmptyStringOrNil.ts
(1 hunks)packages/theme/src/themes/contract.ts
(1 hunks)packages/theme/src/themes/dark.ts
(1 hunks)packages/theme/src/themes/light.ts
(1 hunks)packages/theme/src/tokens/colors.ts
(1 hunks)packages/theme/src/tokens/spacing.ts
(1 hunks)packages/ui/package.json
(1 hunks)packages/ui/src/components/TextField/TextFieldInput.tsx
(1 hunks)
💤 Files with no reviewable changes (1)
- apps/web/src/components/common/ImageManager/index.ts
✅ Files skipped from review due to trivial changes (3)
- apps/web/src/app/create/page.tsx
- apps/web/src/app/create/_components/AnimatedContainer/AnimatedContainer.css.ts
- apps/web/src/app/page.tsx
🔇 Additional comments (19)
apps/web/src/app/create/_components/KeywordChip/context.tsx (2)
3-14
: 타입 정의가 잘 구성되어 있습니다!컨텍스트 값의 타입 정의가 명확하고 포괄적으로 잘 되어 있습니다.
20-28
: useKeywordChip 훅의 에러 처리가 적절합니다.컨텍스트 사용 시 Provider 외부에서 사용되는 것을 방지하는 에러 처리가 잘 구현되어 있습니다.
apps/web/src/app/create/_components/KeywordChip/KeywordChip.css.ts (1)
34-37
: 그룹 래퍼 스타일이 깔끔하게 정의되었습니다!flex 레이아웃과 간격이 적절하게 설정되어 있습니다.
packages/theme/src/tokens/spacing.ts (1)
12-12
: 새로운 spacing 토큰이 올바르게 추가되었습니다!기존 패턴을 잘 따르고 있으며, 일관된 단위(rem)를 사용하고 있습니다.
packages/theme/src/tokens/colors.ts (1)
2-2
: 색상 토큰이 적절하게 업데이트되었습니다!
- primary200 색상이 추가되었고 명명 규칙을 잘 따르고 있습니다.
- primary800 색상값이 업데이트되었습니다.
Also applies to: 6-6
packages/theme/src/themes/contract.ts (1)
35-35
: ThemeContract 타입이 올바르게 확장되었습니다!primary200 색상이 타입 정의에 추가되어 색상 토큰과 일관성이 유지되었습니다.
packages/theme/src/themes/dark.ts (1)
39-39
: 다크 테마에 새로운 색상이 올바르게 구현되었습니다!primary200 색상이 토큰을 올바르게 참조하고 있으며, ThemeContract 타입을 정확히 구현하고 있습니다.
packages/theme/src/themes/light.ts (1)
Line range hint
6-8
: 삭제 예정인 컬러 토큰의 제거 일정을 명확히 해주세요.현재 삭제 예정으로 표시된
primary
,primary400to200
,primaryHover
토큰들이 있습니다. 이러한 기술 부채를 관리하기 위해 다음을 제안드립니다:
- 삭제 일정을 TODO 주석에 명시
- 해당 토큰들의 사용처를 파악하고 마이그레이션 계획 수립
- Issue를 생성하여 추적 관리
다음 스크립트로 삭제 예정인 토큰들의 사용처를 확인할 수 있습니다:
✅ Verification successful
현재 tsx 파일도 포함하도록 glob 패턴을 사용해서 재검증하는 스크립트를 작성했습니다. 이 스크립트를 실행한 결과를 확인하시고, 결과에 따라 삭제 예정 컬러 토큰의 사용 여부를 다시 한 번 검토해 주시기 바랍니다.
검증 결과: 삭제 예정 컬러 토큰이 코드베이스 내에서 다른 곳에 사용되지 않음을 확인했습니다.
packages/theme/src/themes/light.ts
파일에 남아 있는primary
,primary400to200
및primaryHover
토큰은 다른 파일에서 참조되는 흔적이 없습니다.- 현재 해당 토큰들은 상수 정의로 남아 있으며, 삭제 예정이라는 TODO 주석만 달려 있습니다.
- 코드 정리 및 향후 유지보수를 위해 구체적인 삭제 일정 또는 관련 이슈 번호를 주석에 명시하는 것을 권장합니다.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: 삭제 예정인 컬러 토큰들의 사용처 확인 echo "Checking usage of deprecated color tokens..." # primary 토큰 사용처 확인 echo "\nChecking 'primary' token usage:" rg "colors\.primary[^2-9]" --type ts --type tsx # primary400to200 토큰 사용처 확인 echo "\nChecking 'primary400to200' token usage:" rg "colors\.primary400to200" --type ts --type tsx # primaryHover 토큰 사용처 확인 echo "\nChecking 'primaryHover' token usage:" rg "colors\.primaryHover" --type ts --type tsxLength of output: 608
Script:
#!/bin/bash # 새 확인 스크립트: ts 및 tsx 파일에서 deprecated 컬러 토큰 사용처 확인 echo "Deprecated 색상 토큰 사용처 확인 (ts, tsx 파일)..." echo -e "\n'primary' 토큰 사용처 확인:" rg -g "*.ts" -g "*.tsx" "colors\.primary\b" echo -e "\n'primary400to200' 토큰 사용처 확인:" rg -g "*.ts" -g "*.tsx" "colors\.primary400to200\b" echo -e "\n'primaryHover' 토큰 사용처 확인:" rg -g "*.ts" -g "*.tsx" "colors\.primaryHover\b"Length of output: 454
apps/web/src/utils/index.ts (1)
2-2
: 내보내기 구문이 올바르게 구성되었습니다!유틸리티 함수의 내보내기가 일관된 패턴을 따르고 있습니다.
apps/web/src/components/common/index.ts (1)
1-4
: 컴포넌트 내보내기가 잘 구성되었습니다!컴포넌트와 타입 내보내기가 명확하게 구분되어 있으며, 일관된 패턴을 따르고 있습니다.
apps/web/src/app/create/types.ts (2)
3-8
: 타입 정의가 잘 되어있습니다!상수 객체로부터 타입을 추출하는 방식으로 타입 안전성을 보장하고 있습니다.
10-18
: 폼 값 인터페이스가 명확하게 정의되어 있습니다.선택적 필드(
newsCategory
,imageUrls
)가 적절하게 표시되어 있으며, 각 필드의 타입이 명확합니다.apps/web/src/components/common/ImageManager/TypeA/TypeA.css.ts (2)
13-13
: 반응형 스타일링이 개선되었습니다.
width: '100%'
추가로 컨테이너가 부모 요소의 전체 너비를 사용하도록 개선되었습니다.
17-18
: 정렬 로직이 개선되었습니다.
justifyContent
를 사용하여 중앙 정렬과 좌측 정렬을 명확하게 구분하고 있습니다.apps/web/src/components/common/MainBreadcrumbItem/MainBreadcrumbItem.css.ts (1)
16-28
: 테마 시스템이 잘 활용되었습니다.
vars
를 통해 일관된 스페이싱, 색상, 타이포그래피 값을 사용하고 있어 디자인 시스템과의 통일성이 잘 유지되고 있습니다.apps/web/src/components/common/ImageManager/TypeA/UploadedImages.css.ts (1)
34-35
: 포커스 아웃라인 스타일이 적절합니다.rem 단위를 사용하여 일관된 스타일링을 유지하고 있으며, 접근성을 고려한 포커스 아웃라인이 잘 구현되어 있습니다.
apps/web/src/app/create/Create.tsx (1)
33-34
: TODO 항목 구현 계획 수립 필요백엔드 데이터 타입과 presigned URL 관련 TODO 항목이 있습니다. 이러한 기능은 핵심적인 부분이므로 우선순위를 높게 설정하고 구현 계획을 수립해야 합니다.
백엔드 API 스펙이 준비되어 있다면, 해당 기능 구현을 도와드릴 수 있습니다.
apps/web/package.json (1)
17-17
: 추가된 Motion 라이브러리 확인
새로운 의존성"motion": "^11.17.0"
이 추가되었습니다. 해당 라이브러리가 새롭게 도입된 애니메이션 컴포넌트들과 원활하게 연동되는지, 그리고 버전 호환성에 문제가 없는지 꼭 확인해 주세요.packages/ui/package.json (1)
21-21
: Export 구문 단순화 검토
"./styles"
의 export 구문이 객체 형태에서 문자열로 직접 지정되도록 변경되었습니다. 이로 인해 스타일 파일을 import할 때 구문이 간결해지고 일관성이 확보될 것으로 보입니다. 변경 사항이 기존 사용자에게 문제를 일으키지 않는지 추가 확인 부탁드립니다.
export function MainBreadcrumbItem({ | ||
href = '/create', | ||
}: MainBreadcrumbItemProps) { | ||
return ( | ||
<Link href={href} className={styles.insteadTextWrapperStyle}> | ||
<Icon name="stack" size={32} color="grey900" /> | ||
<span className={styles.insteadTextStyle}>Instead</span> | ||
</Link> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
접근성과 유지보수성을 개선할 수 있습니다.
다음 개선사항들을 고려해보세요:
- 접근성 속성 추가 (aria-label)
- 기본값을 상수로 분리
- children prop을 통한 텍스트 주입 지원
+const DEFAULT_HREF = '/create';
+
export function MainBreadcrumbItem({
- href = '/create',
+ href = DEFAULT_HREF,
+ children = 'Instead',
}: MainBreadcrumbItemProps) {
return (
- <Link href={href} className={styles.insteadTextWrapperStyle}>
+ <Link
+ href={href}
+ className={styles.insteadTextWrapperStyle}
+ aria-label="대체 콘텐츠로 이동"
+ >
<Icon name="stack" size={32} color="grey900" />
- <span className={styles.insteadTextStyle}>Instead</span>
+ <span className={styles.insteadTextStyle}>{children}</span>
</Link>
);
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export function MainBreadcrumbItem({ | |
href = '/create', | |
}: MainBreadcrumbItemProps) { | |
return ( | |
<Link href={href} className={styles.insteadTextWrapperStyle}> | |
<Icon name="stack" size={32} color="grey900" /> | |
<span className={styles.insteadTextStyle}>Instead</span> | |
</Link> | |
); | |
} | |
const DEFAULT_HREF = '/create'; | |
export function MainBreadcrumbItem({ | |
href = DEFAULT_HREF, | |
children = 'Instead', | |
}: MainBreadcrumbItemProps) { | |
return ( | |
<Link | |
href={href} | |
className={styles.insteadTextWrapperStyle} | |
aria-label="대체 콘텐츠로 이동" | |
> | |
<Icon name="stack" size={32} color="grey900" /> | |
<span className={styles.insteadTextStyle}>{children}</span> | |
</Link> | |
); | |
} |
@@ -29,7 +29,7 @@ export const TextFieldInput = forwardRef< | |||
( | |||
{ | |||
maxLength = 500, | |||
showCounter = true, | |||
showCounter = false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
마이그레이션 가이드 추가 필요 – breaking change 확인됨
검증 결과, showCounter
prop을 명시적으로 설정하지 않는 부분이 여러 곳에서 발견되었습니다. 이로 인해 해당 컴포넌트를 사용하는 기존 코드들이 이전엔 기본값 true
에 의존했을 가능성이 크며, 기본값 변경(true
→ false
)로 인해 의도치 않은 동작이 발생할 수 있습니다.
- 영향을 받는 파일들
packages/ui/src/components/TextField/TextFieldInput.tsx
packages/ui/src/components/TextField/TextField.tsx
apps/web/src/app/page.tsx
apps/web/src/app/create/Create.tsx
따라서, 위와 같이 사용중인 부분들에 대해서 마이그레이션 가이드를 제공하거나, 기본값 변경을 점진적으로 적용하는 방안을 고려해야 합니다.
🔗 Analysis chain
기본값 변경에 대한 마이그레이션 가이드 필요
showCounter
기본값을 true
에서 false
로 변경하는 것은 breaking change가 될 수 있습니다. 이 컴포넌트를 사용하는 기존 코드에 영향을 줄 수 있으므로, 마이그레이션 가이드를 제공하거나 점진적인 변경을 고려해야 합니다.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: 현재 showCounter prop을 명시적으로 지정하지 않고 사용하는 코드 검색
rg -l "TextField.Input" | xargs rg -l "showCounter" -v
Length of output: 220
const handleRemove = useCallback( | ||
(id: string) => { | ||
setImages((prevImages) => { | ||
const updatedImages = prevImages.filter((image) => image.id !== id); | ||
onChange?.(updatedImages.map((img) => img.file)); // 🔹 삭제 후 File 배열 업데이트 | ||
return updatedImages; | ||
}); | ||
}, | ||
[onChange] | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
메모리 누수 방지를 위한 cleanup 로직 개선 필요
handleRemove
함수에서 이미지가 제거될 때 해당 이미지의 URL.revokeObjectURL
을 호출하여 메모리 누수를 방지해야 합니다.
const handleRemove = useCallback(
(id: string) => {
setImages((prevImages) => {
+ const removedImage = prevImages.find((image) => image.id === id);
+ if (removedImage) {
+ URL.revokeObjectURL(removedImage.preview);
+ }
const updatedImages = prevImages.filter((image) => image.id !== id);
onChange?.(updatedImages.map((img) => img.file));
return updatedImages;
});
},
[onChange]
);
📝 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.
const handleRemove = useCallback( | |
(id: string) => { | |
setImages((prevImages) => { | |
const updatedImages = prevImages.filter((image) => image.id !== id); | |
onChange?.(updatedImages.map((img) => img.file)); // 🔹 삭제 후 File 배열 업데이트 | |
return updatedImages; | |
}); | |
}, | |
[onChange] | |
); | |
const handleRemove = useCallback( | |
(id: string) => { | |
setImages((prevImages) => { | |
const removedImage = prevImages.find((image) => image.id === id); | |
if (removedImage) { | |
URL.revokeObjectURL(removedImage.preview); | |
} | |
const updatedImages = prevImages.filter((image) => image.id !== id); | |
onChange?.(updatedImages.map((img) => img.file)); // 🔹 삭제 후 File 배열 업데이트 | |
return updatedImages; | |
}); | |
}, | |
[onChange] | |
); |
const [images, setImages] = useState<ImageFile[]>( | ||
value.map((file) => ({ | ||
id: crypto.randomUUID(), | ||
file, | ||
preview: URL.createObjectURL(file), | ||
})) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
초기 이미지 로딩 시 에러 처리 추가 필요
URL.createObjectURL
은 실패할 수 있으므로, try-catch 블록으로 감싸서 에러 처리를 추가하는 것이 좋습니다.
const [images, setImages] = useState<ImageFile[]>(
- value.map((file) => ({
- id: crypto.randomUUID(),
- file,
- preview: URL.createObjectURL(file),
- }))
+ value.map((file) => {
+ try {
+ return {
+ id: crypto.randomUUID(),
+ file,
+ preview: URL.createObjectURL(file),
+ };
+ } catch (error) {
+ console.error('이미지 미리보기 생성 실패:', error);
+ return null;
+ }
+ }).filter((image): image is ImageFile => image !== null)
);
📝 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.
const [images, setImages] = useState<ImageFile[]>( | |
value.map((file) => ({ | |
id: crypto.randomUUID(), | |
file, | |
preview: URL.createObjectURL(file), | |
})) | |
); | |
const [images, setImages] = useState<ImageFile[]>( | |
value.map((file) => { | |
try { | |
return { | |
id: crypto.randomUUID(), | |
file, | |
preview: URL.createObjectURL(file), | |
}; | |
} catch (error) { | |
console.error('이미지 미리보기 생성 실패:', error); | |
return null; | |
} | |
}).filter((image): image is ImageFile => image !== null) | |
); |
apps/web/src/app/create/Create.tsx
Outdated
render={({ field }) => ( | ||
<TextField.Input | ||
{...field} | ||
placeholder="주제를 적어주세요" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
잘못된 placeholder 텍스트 수정 필요
핵심 내용 입력 필드의 placeholder가 "주제를 적어주세요"로 잘못 설정되어 있습니다.
- placeholder="주제를 적어주세요"
+ placeholder="핵심 내용을 적어주세요"
📝 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.
placeholder="주제를 적어주세요" | |
placeholder="핵심 내용을 적어주세요" |
const onSubmit = (data: CreateFormValues) => { | ||
//TODO: 임시 로직. 이런 식으로 요청해야 함 | ||
// // 1. presigned URL 요청 | ||
// const presignedUrls = await fetchPresignedUrls(data.imageUrls); // 🔹 presigned URL 요청 | ||
|
||
// // 2. 파일을 presigned URL로 업로드 | ||
// await Promise.all( | ||
// data.imageUrls.map((file, index) => | ||
// uploadFileToPresignedUrl(presignedUrls[index], file) | ||
// ) | ||
// ); | ||
|
||
const presignedUrls = [ | ||
'https://example.com/image1.jpg', | ||
'https://example.com/image2.jpg', | ||
]; | ||
|
||
const requestData = { | ||
...data, | ||
newsCategory: data.reference === 'NEWS' ? data.newsCategory : null, | ||
imageUrls: data.reference === 'IMAGE' ? presignedUrls : null, | ||
}; | ||
|
||
console.log('폼 데이터:', requestData); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
임시 로직 개선 및 에러 처리 추가 필요
현재 구현된 임시 로직에 다음 개선사항이 필요합니다:
- 실제 API 호출 구현
- 로딩 상태 처리
- 에러 처리 및 사용자 피드백
-const onSubmit = (data: CreateFormValues) => {
+const onSubmit = async (data: CreateFormValues) => {
+ try {
+ setIsLoading(true);
+
const presignedUrls = await fetchPresignedUrls(data.imageUrls);
await Promise.all(
data.imageUrls.map((file, index) =>
uploadFileToPresignedUrl(presignedUrls[index], file)
)
);
const requestData = {
...data,
newsCategory: data.reference === 'NEWS' ? data.newsCategory : null,
imageUrls: data.reference === 'IMAGE' ? presignedUrls : null,
};
- console.log('폼 데이터:', requestData);
+ await createContent(requestData);
+ toast.success('컨텐츠가 성공적으로 생성되었습니다');
+ } catch (error) {
+ toast.error('컨텐츠 생성 중 오류가 발생했습니다');
+ console.error(error);
+ } finally {
+ setIsLoading(false);
+ }
};
📝 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.
const onSubmit = (data: CreateFormValues) => { | |
//TODO: 임시 로직. 이런 식으로 요청해야 함 | |
// // 1. presigned URL 요청 | |
// const presignedUrls = await fetchPresignedUrls(data.imageUrls); // 🔹 presigned URL 요청 | |
// // 2. 파일을 presigned URL로 업로드 | |
// await Promise.all( | |
// data.imageUrls.map((file, index) => | |
// uploadFileToPresignedUrl(presignedUrls[index], file) | |
// ) | |
// ); | |
const presignedUrls = [ | |
'https://example.com/image1.jpg', | |
'https://example.com/image2.jpg', | |
]; | |
const requestData = { | |
...data, | |
newsCategory: data.reference === 'NEWS' ? data.newsCategory : null, | |
imageUrls: data.reference === 'IMAGE' ? presignedUrls : null, | |
}; | |
console.log('폼 데이터:', requestData); | |
}; | |
const onSubmit = async (data: CreateFormValues) => { | |
try { | |
setIsLoading(true); | |
const presignedUrls = await fetchPresignedUrls(data.imageUrls); | |
await Promise.all( | |
data.imageUrls.map((file, index) => | |
uploadFileToPresignedUrl(presignedUrls[index], file) | |
) | |
); | |
const requestData = { | |
...data, | |
newsCategory: data.reference === 'NEWS' ? data.newsCategory : null, | |
imageUrls: data.reference === 'IMAGE' ? presignedUrls : null, | |
}; | |
await createContent(requestData); | |
toast.success('컨텐츠가 성공적으로 생성되었습니다'); | |
} catch (error) { | |
toast.error('컨텐츠 생성 중 오류가 발생했습니다'); | |
console.error(error); | |
} finally { | |
setIsLoading(false); | |
} | |
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/src/app/create/Create.tsx
(1 hunks)
🔇 Additional comments (3)
apps/web/src/app/create/Create.tsx (3)
33-34
: TODO 주석 처리 필요백엔드 연동과 관련된 TODO 주석이 있습니다:
- newsCategory의 데이터 타입
- presigned URL 처리
이러한 TODO 항목들을 추적하고 해결하기 위해 이슈를 생성하는 것이 좋겠습니다.
이슈를 생성하여 이러한 TODO 항목들을 추적하시겠습니까?
44-68
: 임시 로직 개선 및 에러 처리 추가 필요현재 구현된 임시 로직에 다음 개선사항이 필요합니다:
- 실제 API 호출 구현
- 로딩 상태 처리
- 에러 처리 및 사용자 피드백
108-108
: 잘못된 placeholder 텍스트 수정 필요핵심 내용 입력 필드의 placeholder가 "주제를 적어주세요"로 잘못 설정되어 있습니다.
<KeywordChipGroup onChange={onChange} defaultValue={value}> | ||
{['투자', '패션', '피트니스', '헬스케어']} | ||
</KeywordChipGroup> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
뉴스 카테고리 하드코딩 개선 필요
뉴스 카테고리가 컴포넌트 내부에 하드코딩되어 있습니다. 이는 유지보수성을 저하시키고 카테고리 변경 시 코드 수정이 필요합니다.
다음과 같이 상수로 분리하는 것을 제안드립니다:
+const NEWS_CATEGORIES = ['투자', '패션', '피트니스', '헬스케어'] as const;
+
<KeywordChipGroup onChange={onChange} defaultValue={value}>
- {['투자', '패션', '피트니스', '헬스케어']}
+ {NEWS_CATEGORIES}
</KeywordChipGroup>
추후에는 이 카테고리 목록을 API를 통해 받아오는 것을 고려해보시기 바랍니다.
📝 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.
<KeywordChipGroup onChange={onChange} defaultValue={value}> | |
{['투자', '패션', '피트니스', '헬스케어']} | |
</KeywordChipGroup> | |
+const NEWS_CATEGORIES = ['투자', '패션', '피트니스', '헬스케어'] as const; | |
<KeywordChipGroup onChange={onChange} defaultValue={value}> | |
- {['투자', '패션', '피트니스', '헬스케어']} | |
+ {NEWS_CATEGORIES} | |
</KeywordChipGroup> |
@@ -14,6 +14,7 @@ | |||
"@repo/theme": "workspace:^", | |||
"@repo/ui": "workspace:^", | |||
"@vanilla-extract/css": "^1.17.0", | |||
"motion": "^11.17.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
p4;
모션 라이브러리 ui, web 모두에서 쓰이니까 최상위로 올려도 될 것 같아요! api 로직 추가 시 고쳐도 될 것 같습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
theme 패키지에서 안쓰여서 motion 의존성은 현재대로 유지하는 게 좋지 않을까 생각됩니다!
<Breadcrumb.Item> | ||
<MainBreadcrumbItem href="/create" /> | ||
</Breadcrumb.Item> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
p4;
MainBreadcrumbItem을 사용할 때 <Breadcrumb.Item/>을 감싸지 않고 사용할 수 있도록 해도 좋을 것 같은데 어떨까요?.?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이게 Breadcrumb의 의도한 사용법이어서요! 유지하도록 하겠습니다!
고생하셨습니다!! |
* [Feat] 프로젝트 스캐폴딩 (#2) * docs: 이슈, PR 템플릿 추가 * docs: codeoners 추가 * feat: web 앱 Next.js, React 버전 다운그레이드 * feat: eslint, tsconfig 종속성, prettier 추가 * feat: husky, lint-staged 설치 * feat: husky, lint-staged 테스트 * chore: husky, lint-staged 테스트 * chore: husky, lint-staged 테스트 2 * fix: eslint config 수정 * chore: husky, lint-staged 테스트 3 * chore: husky, lint-staged 테스트 4 * chore: husky, lint-staged 테스트 5 * feat: .nvmrc 추가 * feat: vanilla extract 설치, config 수정 * chore: web 앱 type: module 설정 제거 * chore: vanilla extract 설치, next.config.js 수정 * [Chore]: 리뷰어 선정 시 슬랙 알림 workflow 적용 (#33) * [Chore]: ui 패키지 초기 셋팅 (#34) * feat(packages/theme): theme 패키지를 생성해요. (#36) * [Chore]: build ci 추가 (#38) * feat: pnpm workspace 추가 (#42) * [Fix]: theme, ui 패키지의 vanilla-extract 빌드 설정 수정 (#45) * fix(apps/web, packages/theme, packages/ui): theme, ui 패키지의 vanilla-extract 빌드 설정, css 관련 수정 * chore(packages/theme, packages/ui): build 스크립트 수정 * chore(packages/theme, packages/ui): exports 수정 * chore(packages/theme, packages/ui): exports 수정 * wip * chore(packages/theme, packages/ui): 불필요 dependency 제거 * chore(packages/theme, packages/ui): 불필요 필드 제거 * fix: 공통 패키지 루트로 끌어올리기, 패키지 버전 의존성 적용 * fix: 테스트 컴포넌트 제거 * fix: 테스트 컴포넌트 제거 * chore(apps/web): 주석처리 * chore: 빌드 테스트 * chore: 테스트용 컴포넌트 제거 --------- Co-authored-by: kangnayeon <[email protected]> * [Feat]: theme 적용을 위한 Provider 추가 (#47) * [Feat] Spacing 컴포넌트 추가 (#49) * [Feat] Icon 컴포넌트 추가 (#48) * feat(packages/ui): Icon 컴포넌트 추가 * fix(packages/ui): 아이콘 속성 camelCase로 수정 * feat(packages/ui): svg 파일 import 스크립트, svgr 플러그인 설정 추가 * feat(packages/ui): Icon 컴포넌트 * fix(packages/theme): color 뎁스 낮추기 * [Feat] Spacing 컴포넌트 추가 (#49) * fix: resolve conflicts * fix(packages/theme): 컬러 토큰 변경에 따른 dark, theme 토큰 변경 * fix: resolve conflicts * chore: 주석 제거 --------- Co-authored-by: minseong <[email protected]> * [Fix] Icon 컴포넌트 수정 (#51) * fix(packages/ui): Icon 컴포넌트 수정 * chore(packages/ui): 색상 스타일 로직 개선 * fix(packages/ui): IconProps의 color 타입을 string으로 수정해요 * [Fix] 컬러 시스템 내의 색상만 사용할 수 있도록 Icon 컴포넌트 수정 (#53) * fix(packages/ui): Icon 컴포넌트 수정 * chore(packages/ui): 색상 스타일 로직 개선 * fix(packages/ui): IconProps의 color 타입을 string으로 수정해요 * fix(packages/ui, apps/web): 컬러 시스템 내의 색상만 사용할 수 있도록 Icon 컴포넌트 수정 * [Fix] Spacing 컴포넌트 수정 (#54) * fix(packages/ui): Spacing 컴포넌트 수정 * chore: name import 하도록 수정 * chore: 배럴 파일 수정 * chore: empty file 삭제 * chore(packages/theme): 색상 추가 (#56) * [Feat] Text 컴포넌트 추가 (#57) * feat(packages/ui): Text 컴포넌트 * feat(packages/ui): 컴파운드 객체 추가 * chore(packages/ui): TypographyType theme에서 가져오도록 수정 * fix(packages/ui): TextCompoundType 선언 시 중복되는 구문 수정 * fix(packages/ui): Compound Text 컴포넌트 선언 시 중복되는 로직 수정 * feat(packages/ui): Text 컴포넌트 사용 시 대문자 사용하도록 수정 * [Feat] Toast 컴포넌트 추가 (#52) * chore(packages/ui): ovarlay-kit 의존성 추가 * feat(packages/ui): Toast 컴포넌트 구현 * test(apps/web): Toast 컴포넌트 사용 예시 추가 * fix(packages/ui): 접근성 개선 * chore(packages/ui): lock 파일 업데이트 * chore(packages/themes): violet 색상 추가 * chore(packages/ui): success일 경우의 색상 변경 * fix(apps/web): Providers 컴포넌트 분리, OverlayProvider 이동 * [Feat] Badge 컴포넌트 구현 (#58) * feat(packages/ui, apps/web): Badge 컴포넌트 구현 * fix(packages/ui, apps/web): Badge 컴포넌트 수정 * chore(packages/ui): named import 변경 * [Feat] Checkbox 컴포넌트 추가 (#60) * feat(packages/ui): 누름 상태 관리를 위한 usePress 추가 * chore(packages/ui): 체크박스 아이콘 추가 * feat(packages/ui): 체크박스 컴포넌트 추가 * chore(apps/web): 사용 예시 추가 * fix(packages/ui): 키보드 접근성 수정 * [Feat] Label 컴포넌트 구현 (#61) * feat(packages/ui): Label 컴포넌트 구현 * chore(packages/ui): Label 컴포넌트 예시 * [Feat] Button 컴포넌트 추가 (#59) * feat(packages/ui): Button 컴포넌트 * fix(packages/ui): Icon color 속성 없을 시 currentColor 적용되도록 수정 * chore(packages/ui): Button 컴포넌트 export * fix(packages/ui): Button 컴포넌트 스타일 * fix(packages/ui): Icon default size 100%로 변경 * fix(packages/ui): Button 컴포넌트의 leftIcon, rightIcon prop을 leftAddon, rightAddon으로 수정 * feat(packages/ui): twincle icon 추가 * fix(packages/ui): 기존 태그의 prop을 상속 받는 경우 ComponentPropsWithoutRef 사용하도록 수정 * [Feat] Breadcrumb 컴포넌트 추가 (#62) * chore(packages/ui): @radix-ui/react-slot 설치 * feat(packages/ui): Breadcrumb 컴포넌트 구현 * test(apps/web): 사용 예시 추가 * [Feat] px -> rem 변환 (#64) * fix: px 단위 rem으로 변환 * fix: body font-size 1.6rem으로 지정 * [Chore] Checkbox 컴포넌트의 label fontSize 변환 (#66) * chore(packages/ui): Checkbox 컴포넌트의 label fontSize 변환 * chore(packages/ui): className 빈 값 string 기본값 지정 * [Feat] LottieAnimation 컴포넌트 추가 (#63) * feat(packages/ui): 로티 파일, 생성 스크립트 추가 * feat(packages/ui): LottieAnimation 컴포넌트 추가 * fix(packages/ui): LottieAnimation 따로 export 하도록 수정, 에셋 상대경로로 수정 * fix(packages/ui): 스크립트 오타 수정 * feat(packages/ui): 코드리뷰 반영 * fix: 빌드 에러 수정 * [Feat] TextField 컴포넌트 구현 (#65) * chore(apps/web): react-hook-form 설치 * feat(packages/ui): isNill 함수 추가 * chore(packages/ui): isNill export * feat(packages/ui): TextField 컴포넌트 구현 * test(apps/web): 예시 추가 * fix(packages/ui): 디자인 요구사항 수정 * [Feat] 아이콘, 색상 변경 사항 반영 (#72) * feat(packages/theme): 아이콘 변경 사항 반영 * fix(packages/ui): 누락된 아이콘 추가 * [Feat] IconButton 컴포넌트 (#68) * [Feat] Spinner 컴포넌트 추가 (#69) * feat(packages/ui): Spinner 컴포넌트 * feat(packages/ui): Spinner span 태그로 감싸기 * fix(packages/ui): SpinnerColorType 추가 * [�Fix]: ThemeProvider 패키지 이동, 불필요 배럴 파일 정리 (#74) * wip * chore(apps/web): 파일 구조 변경 * chore(packages/theme, apps/web): 배럴파일 정리 및 provider 별도 export * chore(packages/theme): provider 별도 export * fix(packages/theme, packages/ui): ThemeProvider 이동 * remove(apps/web): 퍼블리싱 삭제 (별도 PR 예정) * [Feat] RadioCards 컴포넌트 추가 (#73) * feat(packages/ui): RadioCards 관리를 위한 context 추가 * feat(packages/ui): RadioCards 컴포넌트 구현 및 JSDoc 추가 * feat(packages/ui): RadioCards 사용 예시 추가 * fix(packages/ui): RadioCards 구조 변경 * test(packages/ui): RadioCards 예시 변경 * docs(packages/ui): JSDoc 업데이트 * fix(packages/ui): 키보드 접근성 개선 * [Feat] Modal 컴포넌트 추가 (#83) * feat(packages/ui): PortalConsumer 컴포넌트 * feat(packages/ui): PortalConsumer 컴포넌트 * feat(packages/ui): Modal로의 포커스를 위한 FocusTrap 구현 * feat(packages/ui): Modal 컴포넌트 구현 및 JSDoc 작성 * test(apps/web): Modal 컴포넌트 사용 예시 추가 * fix(packages/ui): overlay-kit에서 이미 제공하고 있으므로 PortalConsumer 제거 * [Feat] 스켈레톤 컴포넌트 (#84) * feat(packages/ui): 스켈레톤 컴포넌트 * feat: displayName 속성 추가 * feat: 리뷰 반영 * [Fix] ui 패키지 컴포넌트 사용 시 모든 컴포넌트가 암묵적으로 import 되는 현상 (#79) * fix(packages/ui): 아이콘 생성 스크립트 확장자 변경 * feat(packages/ui) 컴포넌트 별 배럴 파일 생성 * fix: 공통 로직 임포트 경로 수정 * fix(packages/ui): esm 방식만 지원하도록 수정 * chore: 사용되지 않는 컴포넌트 제거 * chore: 사용되지 않는 아이콘 제거 * fix(packages/ui): 사용되지 않는 플러그인 제거 * fix: 빌드 에러 * fix: 빌드 에러 * fix: 빌드 에러 수정 * feat: svgr 라이브러리 제거, 아이콘 컴포넌트 생성 스크립트 추가 * fix: build error * fix: icon 매핑 스크립트 수정 * feat(packages/ui): 컴포넌트 전체 export 추가 * [Feat] Chip 컴포넌트 추가 (#70) * feat(packages/ui): chip 컴포넌트 * [Feat] TextField 컴포넌트 구현 (#65) * chore(apps/web): react-hook-form 설치 * feat(packages/ui): isNill 함수 추가 * chore(packages/ui): isNill export * feat(packages/ui): TextField 컴포넌트 구현 * test(apps/web): 예시 추가 * fix(packages/ui): 디자인 요구사항 수정 * [Feat] 아이콘, 색상 변경 사항 반영 (#72) * feat(packages/theme): 아이콘 변경 사항 반영 * fix(packages/ui): 누락된 아이콘 추가 * feat(packages/ui): chip 컴포넌트 * feat(packages/ui): Chip에 사용되는 아이콘 추가 * fix(packages/ui): Text 컴포넌트 color prop 없을 때 inherit으로 지정, 기본 line height 값 지정 * fix(packages/ui): Icon 컴포넌트 color 상속 시 path 태그 외의 다른 태그들도 상속 받을 수 있도록 수정 * fix(packages/ui): Chip 컴포넌트 스타일 수정 * feat: x 아이콘 color 수정 * feat: onClose 추가 * fix: x 아이콘 호버링 시 cursor pointer로 지정 * feat: 리뷰 반영 * fix(packages/ui): closable 버튼 보이지 않는 문제 * fix: 리뷰 반영 --------- Co-authored-by: MINSEONG KIM <[email protected]> * [Refactor] Spinner 컴포넌트 css 방식으로 변경 (#92) * fix:(packages/ui): Spinner 컴포넌트 css 방식으로 구현 * fix(packages/ui): Button 컴포넌트 스타일 수정, isLoading 상태 스피너 추가 * [Feat] useToast 추가, DynamicLottie 컴포넌트 추가 (#89) * [Feat]: useModal 추가 (#91) * chore(packages/ui): overlay-kit 설치 * feat(packages/ui): useModal 추가 * test(apps/web): useModal 사용 예시 추가 * fix(packages/ui): 옵셔널로 치환 * fix(packages/ui): 자잘한 수정 * fix(packages/ui): 자잘한 수정 * docs(packages/ui): JSDoc 추가 * test(apps/web): 사용 예시 추가 * chore(packages/ui): 코드 간소화 * fix(packages/ui): 프로미스를 반환할 수 있도록 수정 * fix(packages/ui): isNil수정, isNotNill 추가, export 수정 * fix(package/ui): nullish 체크 * fix(packages/ui): 모달 doubleCTA의 각각 버튼 공간이 절반 차지하도록 수정 * test(packages/ui): 예시 수정 * chore: lock 파일 업데이트 * [Feat] ImageManager TypeA 컴포넌트 추가 (#94) * chore(apps/web): Provider -> provider로 변경 (네이밍 컨벤션 통일) * feat(apps/web): ImageManager TypeA 컴포넌트 구현 * chore(apps/web): 대소문자 git 이슈 해결 * chore(apps/web): baseUrl 설정 * fix(apps/web): 자잘한 수정, 접근성 개선 * chore(apps/web): 키 상수화 * fix(apps/web): 유효성 검사 수정 * chore(apps/web): 경로 수정 * [Feat] 주제 설정 페이지 퍼블리싱 및 폼 연동 (#95) * chore(apps/web): motion 추가 * chore(packages/ui): styles export 변경 * feat(packages/theme): 색상 추가 * feat(packages/theme): spacing 추가 * feat(apps/web): KeywordChip 컴포넌트 추가 * feat(apps/web): ImageManager 컴포넌트 추가 * feat(apps/web): 주제 설정 페이지 퍼블리싱 * refactor(apps/web): 컴포넌트 분리 및 자잘한 수정 * fix(apps/web): react-hook-form watch를 통한 조건부 렌더링 * feat(apps/web): react-hook-form을 통한 폼 관리 * fix(apps/web): ImageManager 컴포넌트 packages/ui로 이동 예정 * fix(apps/web): ImageManager TypeA css 수정 * fix(apps/web): GradientAnimatedTitle로 수정 * fix(apps/web): GradientAnimatedTitle로 수정 * feat(apps/web): isEmptyStringOrNil 유틸 추가 * fix(apps/web): ImageManager TypeA 제어형으로 사용 가능하도록 변경 * refactor(apps/web): 컴포넌트 분리 * chore(apps/web): px->rem 변경 * fix(app/web): defaultValues 수정 * fix(apps/web): css 수정 * fix(apps/web): placeholder 수정 * [Feat] ky, tanstack-query 설정, presigned-url 모듈, 뉴스 카테고리 api 연동 (#97) * fix(packages/ui): onClick 누락 수정 * fix(packages/ui): onClick 누락 수정 * feat(apps/web): 필수 항목 입력 후 홈 BreadCrumb 클릭 시 모달 * feat(apps/web): tanstack-query 셋팅 * fix(apps/web): tanstack-query 셋팅 수정 * feat(apps/web): ky 셋팅 * fix(apps/web): KeywordChipGroup 컴포넌트 수정 * feat(apps/web): 뉴스 카테고리 api 연듕 * feat(apps/web): put, patch, delete 추가 * feat(apps/web): put, patch, delete 추가 * fix(apps/web): nullish 검증 * chore(.github/workflows): env 추가 * fix(apps/web): staleTime, gcTime 수정 * fix(apps/web): 자잘한 수정 * fix(apps/web): 토큰 string으로 관리 * chore(apps/web): shared로 폴더명 변경 * feat(apps/web): presigned-url 모듈 구현 및 연동 * [Feat] 주제 설정 페이지 api 연동, 디자인 추가 반영 (#100) * fix(apps/web): MainBreadcrumbItem 이미지 수정 * fix(apps/web): suspense 래핑 * remove(apps/web): 불필요 코드 제거 * feat(apps/web): 스크롤 감지 훅 추가 * feat(apps/web): 반투명 NavBar 추가 * fix(apps/web): 스타일링 수정 * fix(apps/web): 스타일링 수정 * fix(apps/web): ImageManager TypeA가 File이 아닌 이미지의 url로 받도록 수정 * feat(apps/web): 공통 타입 분리 * feat(apps/web): 게시물 그룹 및 게시물 생성 API 연동 * feat(apps/web): ImageManager TypeA 최적화 및 UI만 그리도록 관심사 분리 * fix: Images 폴더명을 images로 수정 * fix(apps/web): 자잘한 수정 * fix(apps/web): 자잘한 수정 * fix(apps/web): 타입 개선 * fix(apps/web): ImageManager 단일로 관리 * [Feat] Accordion 컴포넌트 (#99) * fix(packages/ui): Chip 컴포넌트 개별 export * feat(packages/ui): Accordion 컴포넌트 * chore: Accordion 컴포넌트 예시 추가 * chore(packages/ui): displayName 추가 * fix: 코드리뷰 반영 * fix: resolve conflicts * [Fix] 컴포넌트 스타일 수정 (#102) * fix: 폴더명 Images를 images로 변경 * fix(apps/web): 간단한 레이아웃 수정 * fix(apps/web): NavBar 레이아웃 수정 * fix(packages/ui, apps/web): TextField 레이아웃 깨짐 수정 * fix(packages/ui): Checkbox width 수정 * docs(packages/ui): TextField JSDoc 수정 * [Feat] 결과 수정 - 상세 페이지 퍼블리싱 (#86) * feat(apps/web): ContentItem 컴포넌트 * feat(apps/web): getMinutesAgo 유틸 함수 추가 * feat(apps/web): ContentItem 컴포넌트 * fix(packages/ui): Chip 컴포넌트 개별 export * feat(packages/ui): Accordion 컴포넌트 * chore: Accordion 컴포넌트 예시 추가 * feat(apps/web): EditSidebar 추가 * feat(packages/ui): 아이콘 에셋 추가 * fix(apps/web): getMinutesAgo 함수 getTimesAgo 함수로 수정 * fix(packages/ui): IconButton 컴포넌트 props에서 type도 받도록 수정 * fix(apps/web): ContentItem 컴포넌트 디자인 수정 반영 * feat(apps/web): PostEditor 추가 * feat(apps/web): EditPromptField 추가 * feat(apps/web) EditPost 영역 추가 * feat(apps/web): ContentItem 컴포넌트 * chore: Accordion 컴포넌트 예시 추가 * fix: resolve conflicts * fix: resolve conflicts * fix: 빌드 에러 * fix: 빌드 에러 * fix(apps/web): TextField 수정 반영 * fix(packages/ui): Accordion 컴포넌트 스타일 수정 * [Feat] vercel 자동 배포 빌드 스크립트 (#105) --------- Co-authored-by: MINSEONG KIM <[email protected]> Co-authored-by: minseong <[email protected]>
관련 이슈
close: #77
변경 사항
주제 설정 페이지를 퍼블리싱했어요. 그리고 react-hook-form을 활용해 폼 데이터 관리를 진행했어요. 백엔드에게 post로 요청해야하는 인터페이스를 바탕으로 구성했어요.
비제어로 활용가능한 부분도 있으나(예: 핵심 내용 텍스트 필드), 생성하기 버튼 활성화/비활성화 여부, 생성 방식 라디오 카드 선택에 따른 추가 폼 조건부 렌더링이 있어 통일을 위해 폼 전체를 제어 방식으로 구현했어요.
그리고 폼 관리와 관련해 코드가 상당히 길어 읽기 힘든데, 응집도를 위해 따로 분리하지 않았고 중복 UI 로직을 줄이기 위해 constants로 관리함으로써 코드의 가독성을 개선했어요.
공통으로 활용가능한 부분은 components/common, utils에 분리해두었습니다!
2025-02-01.8.02.39.mov
레퍼런스
Summary by CodeRabbit
릴리즈 노트
새로운 기능
Create
컴포넌트 및 관련 상수 추가ImageManager
컴포넌트 업데이트 및 새로운 속성 추가UI 개선
테마 및 스타일
primary200
추가MainBreadcrumbItem
및AnimatedContainer
스타일 추가