Conversation
|
Caution Review failedThe pull request is closed. WalkthroughNext.js 의존성( Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: ASSERTIVE Plan: Pro ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (2)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
package.json (1)
57-63: Next 16.0.7 보안 패치 적용은 적절하지만, React/Node/서드파티 버전 정합성 점검이 필요합니다
- Next 보안 공지 기준으로 15.x/16.x App Router RCE 이슈(CVE-2025-66478)는 16.0.7에서 패치되므로, 15.3.4 → 16.0.7 업그레이드는 방향 자체는 매우 적절합니다.(nextjs.org)
- 다만 Next 16은 최소 Node 20.9.0+, TypeScript 5.1+를 요구하므로(현재 TS 5.2.2는 OK), 로컬/서버/CI Node 버전이 20.9 이상인지 한 번 확인해 두는 편이 안전합니다.(nextjs.org)
- Next 16 공식 가이드는
next@latest로 올릴 때react,react-dom도 함께 최신으로 올릴 것을 권장합니다. 현재 여전히react/react-dom이 18.2.0인 상태라, 의존성 해상 결과에 따라 React 18/19가 섞여 로딩되거나 경고가 발생할 여지가 있습니다. (예:npm install next@latest react@latest react-dom@latest예시).(nextjs.org)@next/third-parties역시 공식 문서에서 항상@next/third-parties@latest next@latest조합으로 설치하라고 권장하고 있어, Next를 16.x로 올린 김에 해당 패키지도 최신 버전으로 정렬하는 것을 추천드립니다.(nextjs.org)- Next 16에서는
cookies(),headers(),draftMode,params,searchParams등 Request API의 동기 접근이 완전히 제거되어 비동기 API만 허용되므로, 기존 코드에서 이들 API를 사용 중이면 한 번 전역 검색 후 마이그레이션 여부를 확인해 보시는 게 좋습니다.(nextjs.org)위 네 가지(React/ReactDOM 버전, Node 런타임 버전,
@next/third-parties버전, Request API 사용처)는 실제 환경에서next build/next start를 돌려 보면서 경고나 에러가 없는지 꼭 한 번 검증해 주세요.tsconfig.json (1)
1-66: tsconfig 확장은 전반적으로 Next 권장 설정과 잘 맞지만,target/jsx값은 한 번 점검해 보는 것을 추천드립니다
paths정리,noEmit: true,module: "esnext",moduleResolution: "node",resolveJsonModule,isolatedModules등은 Next + TS 환경에서 일반적으로 권장되는 설정이라 방향이 좋습니다.include에".next/types/**/*.ts"가 들어가 있고,next-env.d.ts,**/*.ts,**/*.tsx를 포함하는 구조는 Next 공식 TypeScript 문서에서 링크/라우트 타입 생성을 위해 안내하는 패턴과 일치합니다.(nextjs.org)- 다만 Next 16 최소 런타임이 Node 20.9+ 및 최신 브라우저(Chrome/Edge/Firefox 111+, Safari 16.4+) 기준이라, 타입 시스템 관점에서도
target: "es5"대신"es2020"또는"esnext"정도로 올려 두는 편이 더 현실 환경에 가깝고, 최신 JS 내장 객체/메서드에 대한 타입 추론도 좋아집니다. (실제 JS 출력은 SWC가 담당하고noEmit: true라 빌드에는 영향이 없고 타입 정의에만 영향을 줍니다.)(nextjs.org)"jsx": "react-jsx"는 Next가 기본적으로 생성하는tsconfig.json의"jsx": "preserve"와는 다른 값입니다.noEmit: true인 만큼 SWC 번들 결과에는 직접 영향이 없겠지만,tsc --noEmit를 별도로 돌리거나 에디터에서 타입스크립트 언어 서비스를 사용할 때 JSX 처리 방식이 Next 가이드와 달라질 수 있습니다. 공식 예제와 맞추고 싶다면"jsx": "preserve"로 되돌리는 것도 한 가지 옵션입니다.(nextjs.org)요약하면 현재 설정도 동작에는 큰 문제 없을 가능성이 높지만,
target을 최소 ES2020 이상으로 상향,jsx를 유지할지/preserve로 되돌릴지 결정한 뒤next build및tsc --noEmit를 한 번씩 돌려 경고나 타입 에러가 없는지 확인해 보시는 것을 권장드립니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (5)
package-lock.jsonis excluded by!**/package-lock.jsonpublic/skills/vercel.pngis excluded by!**/*.pngpublic/skills/vite.pngis excluded by!**/*.pngpublic/skills/vue.pngis excluded by!**/*.pngpublic/test.svgis excluded by!**/*.svg
📒 Files selected for processing (9)
package.json(1 hunks)src/app/(contents)/projects/haruWeather/HaruWeather.tsx(1 hunks)src/app/(contents)/projects/haruWeather/page.tsx(1 hunks)src/app/(contents)/projects/pushServer/PushServer.tsx(1 hunks)src/app/(contents)/projects/pushServer/page.tsx(1 hunks)src/app/layout.tsx(1 hunks)src/lib/json/mainProjects.json(2 hunks)src/styles/toast.scss(1 hunks)tsconfig.json(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/app/(contents)/projects/pushServer/PushServer.tsx (2)
src/lib/stores/store.ts (1)
useCoreStore(6-15)src/app/(contents)/projects/Projects.tsx (1)
ReactElement(15-73)
src/app/(contents)/projects/pushServer/page.tsx (10)
src/app/(contents)/projects/imsPart1/page.tsx (1)
JSX(3-5)src/app/(contents)/projects/ltcga/page.tsx (1)
ReactElement(4-6)src/app/(contents)/projects/page.tsx (1)
JSX(3-5)src/app/(contents)/donate/page.tsx (1)
JSX(1-3)src/app/(contents)/notice/page.tsx (1)
JSX(1-3)src/app/(contents)/projects/hectonTechblog/page.tsx (1)
JSX(3-5)src/app/(contents)/visitor/page.tsx (1)
JSX(3-5)src/app/login/page.tsx (1)
Page(4-6)src/app/(mydata)/research/page.tsx (1)
ReactElement(4-6)src/app/(mydata)/certification/page.tsx (1)
ReactElement(4-6)
src/app/(contents)/projects/haruWeather/HaruWeather.tsx (1)
src/lib/stores/store.ts (1)
useCoreStore(6-15)
🔇 Additional comments (9)
src/styles/toast.scss (1)
3-5: Toast 전역 폰트 사이즈 설정은 자연스러워 보입니다루트
.Toastify에$small-font를 지정해서 라이브러리 기본값을 맞춰주는 방향은 괜찮아 보입니다. 이미.Toastify__toast-body에 동일한 크기가 적용되어 있어서 실제 텍스트 크기는 크게 변하지 않을 것이지만, 제목/버튼 등 다른 요소에 미세한 레이아웃 변화가 있을 수 있으니 실제 토스트를 띄워서 모바일/데스크톱에서 한 번씩만 눈으로 확인해 보시면 좋겠습니다.src/app/layout.tsx (1)
56-59: Toast autoClose 9999ms 설정이 UX 의도와 맞는지 한 번만 확인해 주세요이제 토스트가 약 10초 동안 유지되기 때문에, 알림을 충분히 읽을 수 있다는 장점은 있지만 짧은 알림이 자주 뜨는 화면에서는 오래 남아서 시야를 가릴 수도 있습니다. “조금 더 오래 보이지만 결국은 자동으로 사라지는” 것이 의도였다면 현재 값으로 충분해 보이고, 사실상 수동 닫기를 원했다면
autoClose={false}도 고려해 볼 수 있습니다. 실제 사용 시나리오(모바일/데스크톱 모두) 기준으로 한번 UX를 점검해 주세요.src/app/(contents)/projects/haruWeather/page.tsx (1)
1-8: HaruWeather page 래퍼 구성은 기존 라우트 패턴과 잘 맞습니다
HaruWeather를 별도 page 컴포넌트로 감싸서 기본 export 하는 구조가 다른(contents)/projects/*/page.tsx들과 일관되고, 타입도ReactElement로 명시되어 있어 유지보수 측면에서도 무난합니다.src/app/(contents)/projects/pushServer/page.tsx (1)
1-9: PushServer page 추가도 기존 구조와 일관되고, 프로젝트 리스트 URL과 잘 연결됩니다
PushServer를page컴포넌트로 감싸서 기본 export 하는 패턴이 다른 페이지들과 동일하고,src/lib/json/mainProjects.json에서 id 8의url을/projects/pushServer로 지정해 둔 부분과도 라우트 경로가 정확히 일치합니다. 이 상태라면 프로젝트 목록에서 해당 항목 클릭 시 이 페이지로 자연스럽게 연결될 것으로 보입니다.src/lib/json/mainProjects.json (1)
56-60: 프로젝트 메타데이터 변경 내용이 라우트/페이지들과 잘 정합됩니다
- id 3의
logos[1].height를 30→20으로 줄인 변경은 순수하게 시각적 조정이라 데이터 구조나 기능 측면 문제는 없어 보입니다.- id 8
"또하나의가족, 플랫폼 고도화 - 푸시서버 구축"의url을"/projects/pushServer"로 설정한 부분은 새로 추가된src/app/(contents)/projects/pushServer/page.tsx라우트와 정확히 매칭됩니다.- 새 id 9
"Haru Weather"항목 역시url: "/projects/haruWeather"로 설정되어 있고, 해당 경로에haruWeather/page.tsx가 존재하므로 프로젝트 리스트 → 상세 페이지 네비게이션이 자연스럽게 동작할 것으로 보입니다.전체적으로 JSON 구조와 라우트 구조가 잘 맞춰져 있어서, 이 파일 변경은 그대로 승인해도 무방해 보입니다.
Also applies to: 150-166
src/app/(contents)/projects/pushServer/PushServer.tsx (4)
1-12: 임포트 구문은 적절합니다.클라이언트 컴포넌트 지시어와 필요한 의존성들이 올바르게 임포트되어 있습니다.
180-191: 중첩된 TextBasic 컴포넌트 구조를 검토하세요.라인 182-190에서
TextBasic컴포넌트 내부에 다른TextBasic컴포넌트들이 중첩되어 있습니다. 이 구조가 의도된 것인지 확인이 필요합니다. 일반적으로 리스트 아이템은 별도의 요소로 렌더링하는 것이 더 적절합니다.다음과 같이 구조를 개선하는 것을 고려하세요:
- <TextBasic size="small"> - {" - 총 3가지 로직 개발"} - <TextBasic size="small"> - {"1) 한 번이라도 요양상담의 답변을 받은 유저에게 매주 월요일 대량발송"} - </TextBasic> - <TextBasic size="small"> - {"2) 요양상담을 접수하지 않고 이탈한 사용자에게 익일 대량발송"} - </TextBasic> - <TextBasic size="small"> - {"3) 한 주 간 조회수가 가장 높았던 요양정보를 금요일에 일괄발송"} - </TextBasic> - </TextBasic> + <TextBasic size="small">{" - 총 3가지 로직 개발"}</TextBasic> + <TextBasic size="small"> + {"1) 한 번이라도 요양상담의 답변을 받은 유저에게 매주 월요일 대량발송"} + </TextBasic> + <TextBasic size="small"> + {"2) 요양상담을 접수하지 않고 이탈한 사용자에게 익일 대량발송"} + </TextBasic> + <TextBasic size="small"> + {"3) 한 주 간 조회수가 가장 높았던 요양정보를 금요일에 일괄발송"} + </TextBasic>
36-147: All image files referenced in the component exist in the public directory. No missing files detected.Likely an incorrect or invalid review comment.
1-1: > Likely an incorrect or invalid review comment.
| <img src="/myFace.png" alt="logo" width={30} height={30} /> | ||
| </div> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's read the HaruWeather.tsx file to understand its content
cat -n src/app/\(contents\)/projects/haruWeather/HaruWeather.tsxRepository: basilry/kbslBlog
Length of output: 10778
🏁 Script executed:
# Let's verify the PicsTemplate to understand what solutionPics vs haruWeatherPics would be
find . -type f -name "PicsTemplate*" | head -20Repository: basilry/kbslBlog
Length of output: 106
🏁 Script executed:
cat -n src/app/\(contents\)/projects/PicsTemplate.tsx | head -100Repository: basilry/kbslBlog
Length of output: 2210
🏁 Script executed:
# Check what pic directories exist to confirm naming pattern
find . -type d -name "*Pics" -o -name "*pics" | grep -v node_modulesRepository: basilry/kbslBlog
Length of output: 175
🏁 Script executed:
# Check other projects to understand the domain naming pattern
ls -la public/solutionPics/ | head -20Repository: basilry/kbslBlog
Length of output: 805
HaruWeather 상세 내용과 이미지 경로에서 Solution 프로젝트로부터의 복붙 흔적이 있으며, 접근성 이슈가 여러 곳에 있습니다
-
"설명"과 "포지션" 섹션은 Haru Weather(개인 사이드 프로젝트, OpenWeather API, Vue3/Vite)에 맞게 작성되어 있으나, "프로젝트 인원"(F/E: 4명, B/E: 2명)과 "성과" 섹션의 "프로젝트 관리자 시스템 개발", "총 84개 페이지 중 31개 신규 페이지", "AWS EC2/ELB 관리" 등의 내용은 기존 Solution 프로젝트 설명을 그대로 복붙한 것으로 보입니다. 포트폴리오 독자의 혼동을 피하려면, 이 부분을 Haru Weather에서 실제로 얻은 성과나 배운 점으로 다시 작성해 주시기 바랍니다.
-
사용스택 섹션의 기술 아이콘들(vite, vue, typescript, sass, prettier, eslint, vercel)의
alt속성이 모두 "myFace"로 설정되어 있으며, 상단 로고 이미지도 alt="logo"로 되어 있습니다. 스크린리더 접근성을 위해 실제 기술 이름(예: "vite", "vue", "TypeScript")으로 변경해 주세요. -
이미지 영역에서
PicsTemplate filePath={"solutionPics"} domainName={"sol"}를 사용하고 있는데, 이는 Solution 프로젝트용 리소스입니다. 현재 설정으로는/solutionPics/sol1.png형태의 Solution 프로젝트 스크린샷을 불러오게 되므로, Haru Weather 전용 이미지 세트를 별도로 준비하고 filePath/domainName을 적절히 수정해 주시기 바랍니다.
🤖 Prompt for AI Agents
In src/app/(contents)/projects/haruWeather/HaruWeather.tsx around lines 37–38,
the file contains leftover Solution-project content and accessibility issues:
replace any copied "프로젝트 인원" and "성과" text with Haru Weather–specific
team/impact/learned-items (or remove if not applicable), update all image alt
attributes (logo and tech icons) from generic values like "logo" or "myFace" to
the actual names (e.g., "Haru Weather logo", "Vite", "Vue 3", "TypeScript",
"Sass", "Prettier", "ESLint", "Vercel") for screen-reader accessibility, and
change the PicsTemplate props (filePath/domainName) from the Solution values
("solutionPics"/"sol") to Haru Weather–specific ones (e.g., "haruPics"/"haru" or
appropriate folder names) so the component loads Haru Weather screenshots
instead of Solution images.
| <div className={styles.list}> | ||
| <Link href={"/projects"} className={classNames(styles.link, darkMode && styles.dark)}> | ||
| <img src={`/${darkMode ? "link_white" : "link"}.svg`} alt={"link"} width={15} /> | ||
| <TextBasic size={"medium"} bold={"bold"}> | ||
| 프로젝트 목록 | ||
| </TextBasic> | ||
| </Link> | ||
| </div> |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Next.js Image 컴포넌트를 일관되게 사용하세요.
라인 20에서 <img> 태그를 사용하고 있는데, 라인 37에서는 Next.js의 Image 컴포넌트를 사용하고 있습니다. 성능 최적화와 자동 이미지 최적화를 위해 Next.js의 Image 컴포넌트를 일관되게 사용하는 것이 좋습니다.
다음과 같이 수정하세요:
- <img src={`/${darkMode ? "link_white" : "link"}.svg`} alt={"link"} width={15} />
+ <Image src={`/${darkMode ? "link_white" : "link"}.svg`} alt={"link"} width={15} height={15} />📝 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.
| <div className={styles.list}> | |
| <Link href={"/projects"} className={classNames(styles.link, darkMode && styles.dark)}> | |
| <img src={`/${darkMode ? "link_white" : "link"}.svg`} alt={"link"} width={15} /> | |
| <TextBasic size={"medium"} bold={"bold"}> | |
| 프로젝트 목록 | |
| </TextBasic> | |
| </Link> | |
| </div> | |
| <div className={styles.list}> | |
| <Link href={"/projects"} className={classNames(styles.link, darkMode && styles.dark)}> | |
| <Image src={`/${darkMode ? "link_white" : "link"}.svg`} alt={"link"} width={15} height={15} /> | |
| <TextBasic size={"medium"} bold={"bold"}> | |
| 프로젝트 목록 | |
| </TextBasic> | |
| </Link> | |
| </div> |
| <TextBasic size="xxx-large" bold="bold"> | ||
| {"또하나의가족, 플랫폼 전반 핑거푸시 외부 API 연동 및 로직 개발"} | ||
| </TextBasic> | ||
| <br /> |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
CSS 마진을 사용하여 간격을 조정하는 것을 고려하세요.
여러 위치에서 <br /> 태그를 사용하여 수직 간격을 조정하고 있습니다. 유지보수성과 일관성을 위해 CSS 마진이나 패딩을 사용하는 것이 더 좋습니다.
예를 들어, 스타일 모듈에 다음과 같은 클래스를 추가할 수 있습니다:
.sectionSpacing {
margin-bottom: 1.5rem;
}
.paragraphSpacing {
margin-bottom: 2rem;
}그리고 컴포넌트에서 다음과 같이 사용하세요:
<div className={styles.sectionSpacing}>
<TextBasic size="large" bold="bold">
{"설명"}
</TextBasic>
{/* ... */}
</div>Also applies to: 41-41, 52-53, 60-61, 149-150, 156-157, 176-176, 192-192, 201-201
| <div className={styles.logos}> | ||
| <img src="/hecton.png" alt="logo" width={30} height={20} /> | ||
| <Image src="/ddoga_logo.svg" alt="logo" width={120} height={30} /> | ||
| </div> |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
이미지 컴포넌트 사용을 통일하세요.
라인 36에서 <img> 태그를 사용하고 라인 37에서 Next.js Image 컴포넌트를 사용하는 등 일관성이 없습니다. 모든 이미지에 대해 Next.js Image 컴포넌트를 사용하여 최적화 혜택을 받으세요.
다음과 같이 수정하세요:
- <img src="/hecton.png" alt="logo" width={30} height={20} />
+ <Image src="/hecton.png" alt="logo" width={30} height={20} />📝 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.
| <div className={styles.logos}> | |
| <img src="/hecton.png" alt="logo" width={30} height={20} /> | |
| <Image src="/ddoga_logo.svg" alt="logo" width={120} height={30} /> | |
| </div> | |
| <div className={styles.logos}> | |
| <Image src="/hecton.png" alt="logo" width={30} height={20} /> | |
| <Image src="/ddoga_logo.svg" alt="logo" width={120} height={30} /> | |
| </div> |
🤖 Prompt for AI Agents
In src/app/(contents)/projects/pushServer/PushServer.tsx around lines 35 to 38,
the code mixes a native <img> tag and Next.js Image component; replace the
native <img> with Next.js Image for consistency and optimization. Import Image
from 'next/image' if not already imported, swap the <img src="/hecton.png"
alt="logo" width={30} height={20} /> with an Image component using the same src,
alt, width and height props, and ensure any parent styling still applies (or
adjust className) so the image renders correctly.
| <img | ||
| className={styles.skillImgs} | ||
| src="/skills/typescript.svg" | ||
| alt="myFace" | ||
| sizes={"100vw"} | ||
| width={60} | ||
| height={60} | ||
| /> | ||
| <img | ||
| className={styles.skillImgs} | ||
| src="/skills/nextjs.svg" | ||
| alt="myFace" | ||
| sizes={"100vw"} | ||
| width={60} | ||
| height={60} | ||
| /> | ||
| <img | ||
| className={styles.skillImgs} | ||
| src="/skills/sass.svg" | ||
| alt="myFace" | ||
| sizes={"100vw"} | ||
| width={60} | ||
| height={60} | ||
| /> | ||
| <img | ||
| className={styles.skillImgs} | ||
| src="/skills/zustand.png" | ||
| alt="myFace" | ||
| sizes={"100vw"} | ||
| width={60} | ||
| height={60} | ||
| /> | ||
| <img | ||
| className={styles.skillImgs} | ||
| src="/skills/prettier.svg" | ||
| alt="myFace" | ||
| sizes={"100vw"} | ||
| width={60} | ||
| height={60} | ||
| /> | ||
| <img | ||
| className={styles.skillImgs} | ||
| src="/skills/eslint.svg" | ||
| alt="myFace" | ||
| sizes={"100vw"} | ||
| width={60} | ||
| height={60} | ||
| /> | ||
| <img | ||
| className={styles.skillImgs} | ||
| src="/skills/mysql.png" | ||
| alt="myFace" | ||
| sizes={"100vw"} | ||
| width={60} | ||
| height={60} | ||
| /> | ||
| <img | ||
| className={styles.skillImgs} | ||
| src="/skills/aws.svg" | ||
| alt="myFace" | ||
| sizes={"100vw"} | ||
| width={60} | ||
| height={60} | ||
| /> | ||
| </div> | ||
| <div> | ||
| <img | ||
| className={styles.skillImgs} | ||
| src="/skills/nodejs.png" | ||
| alt="myFace" | ||
| sizes={"100vw"} | ||
| width={60} | ||
| height={60} | ||
| /> | ||
| <img | ||
| className={styles.skillImgs} | ||
| src="/skills/expressjs.png" | ||
| alt="myFace" | ||
| sizes={"100vw"} | ||
| width={60} | ||
| height={60} | ||
| /> |
There was a problem hiding this comment.
잘못된 alt 텍스트를 수정하고 코드 중복을 제거하세요.
모든 스킬 이미지의 alt 텍스트가 "myFace"로 설정되어 있는데, 이는 접근성 측면에서 심각한 문제입니다. 각 이미지는 "TypeScript", "Next.js", "SASS" 등 실제 기술 이름을 alt 텍스트로 가져야 합니다.
또한, 동일한 패턴의 이미지 렌더링 코드가 반복되고 있어 유지보수가 어렵습니다.
해결 방법 1: 데이터 기반 접근 방식으로 리팩토링
컴포넌트 상단에 스킬 데이터를 정의하세요:
const skills = [
{ src: "/skills/typescript.svg", alt: "TypeScript" },
{ src: "/skills/nextjs.svg", alt: "Next.js" },
{ src: "/skills/sass.svg", alt: "SASS" },
{ src: "/skills/zustand.png", alt: "Zustand" },
{ src: "/skills/prettier.svg", alt: "Prettier" },
{ src: "/skills/eslint.svg", alt: "ESLint" },
{ src: "/skills/mysql.png", alt: "MySQL" },
{ src: "/skills/aws.svg", alt: "AWS" },
]
const backendSkills = [
{ src: "/skills/nodejs.png", alt: "Node.js" },
{ src: "/skills/expressjs.png", alt: "Express.js" },
]그리고 렌더링 부분을 다음과 같이 변경하세요:
- <div>
- <img
- className={styles.skillImgs}
- src="/skills/typescript.svg"
- alt="myFace"
- sizes={"100vw"}
- width={60}
- height={60}
- />
- {/* ... 반복되는 img 태그들 ... */}
- </div>
+ <div>
+ {skills.map((skill) => (
+ <Image
+ key={skill.src}
+ className={styles.skillImgs}
+ src={skill.src}
+ alt={skill.alt}
+ width={60}
+ height={60}
+ />
+ ))}
+ </div>
+ <div>
+ {backendSkills.map((skill) => (
+ <Image
+ key={skill.src}
+ className={styles.skillImgs}
+ src={skill.src}
+ alt={skill.alt}
+ width={60}
+ height={60}
+ />
+ ))}
+ </div>
Summary by CodeRabbit
신기능
업데이트
개선사항
기타
✏️ Tip: You can customize this high-level summary in your review settings.