-
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
Projects 페이지 퍼블리싱#9 #10
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
""" Walkthrough이번 변경 사항은 모션 라이브러리 도입을 위한 준비로, README와 package.json에 모션 관련 뱃지 및 의존성을 추가하고 다양한 UI 컴포넌트를 새로운 디렉토리 구조( Changes
Sequence Diagram(s)sequenceDiagram
participant 사용자 as 사용자
participant 페이지 as Page 컴포넌트
participant 감시자 as SectionWatcher
participant 저장소 as ActiveSectionStore
사용자->>페이지: 페이지 스크롤
페이지->>감시자: 각 섹션 렌더링
감시자->>저장소: activate(sectionId) 호출
저장소-->>감시자: 활성 섹션 업데이트
감시자->>저장소: deactivate(sectionId) 호출
Poem
✨ Finishing Touches
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: 16
🧹 Nitpick comments (11)
src/app/_sections/ContactSection/ContactSection.tsx (1)
3-12
: 실제 연락처 섹션 컨텐츠 구현 필요현재는 "ContactSection" 텍스트만 표시되고 있습니다. 연락처 정보, 소셜 미디어 링크, 또는 연락 양식 등 실제 컨텐츠를 구현해 주세요.
연락처 섹션에 필요한 컴포넌트 구현을 도와드릴까요?
src/app/_sections/IntroSection/IntroSection.tsx (1)
7-9
: 섹션 ID 상수화 권장하드코딩된 섹션 ID를 상수로 관리하면 재사용성과 유지보수성이 향상됩니다.
섹션 ID를 위한 상수 파일을 생성하고 다음과 같이 수정하는 것을 추천드립니다:
+import { SECTION_ID } from '@/constants'; - sectionId="intro" + sectionId={SECTION_ID.intro}src/app/_components/Header/HeaderProgress.tsx (1)
9-21
: 접근성 개선 필요스크롤 진행 상태를 나타내는 요소에 접근성 레이블이 없습니다.
다음과 같이 aria-label을 추가하여 접근성을 개선해 주세요:
<motion.div + role="progressbar" + aria-label="가로 스크롤 진행률" style={{ scaleX: scrollYProgress, }} className="z-10 h-1 origin-left bg-primary2 max-tablet:hidden" ></motion.div> <motion.div + role="progressbar" + aria-label="세로 스크롤 진행률" style={{ scaleY: scrollYProgress, }} className="z-10 w-1 origin-top bg-primary2 tablet:hidden" ></motion.div>src/app/_components/SlideInView/SlideInView.tsx (1)
9-29
: 애니메이션 구현이 잘 되어있습니다.다만, 성능 최적화를 위해 다음과 같은 개선을 제안합니다:
- 하드웨어 가속을 위해 transform 속성 사용
- will-change 속성 추가
<motion.div - initial={{ opacity: 0, translateY: 30 }} + initial={{ opacity: 0, transform: 'translateY(30px)' }} whileInView={{ opacity: 1, - translateY: 0, + transform: 'translateY(0)', transition: { duration: 0.7, delay, }, }} - viewport={{ once: true, amount: 0.3 }} + viewport={{ once: true, amount: 0.3 }} + style={{ willChange: 'transform, opacity' }} >src/app/_sections/SkillsSection/SkillsSection.tsx (1)
11-18
: 애니메이션 딜레이 로직 개선이 필요합니다.현재 짝수/홀수 인덱스에 따른 고정된 딜레이 값 대신, 더 자연스러운 시차 효과를 위해 동적인 딜레이 계산을 제안합니다.
{SKILL_CONTENTS.map((skill, idx) => ( <SlideInView key={`ski-${skill.title}`} - delay={idx % 2 === 0 ? 0 : 0.5} + delay={idx * 0.2} > <Skill skill={skill} /> </SlideInView> ))}src/app/_components/Header/HeaderNav.tsx (1)
8-14
: 상수를 컴포넌트 외부로 이동 권장
NAV_ITEMS
상수를 컴포넌트 외부로 이동하면 불필요한 재생성을 방지하고 메모리 사용을 최적화할 수 있습니다.+const NAV_ITEMS: TSectionId[] = ['intro', 'skills', 'experiences', 'projects', 'contact'] as const; function HeaderNav() { - const NAV_ITEMS: TSectionId[] = ['intro', 'skills', 'experiences', 'projects', 'contact']; // ... rest of the component }src/app/_sections/ProjectsSection/ProjectsSection.tsx (2)
20-20
: 스크롤 계산식 최적화 필요현재 스크롤 위치 계산식이 복잡하고 이해하기 어렵습니다. 가독성과 유지보수성을 위해 계산식을 상수나 함수로 분리하는 것이 좋습니다.
+ const calculateScrollOffset = (count: number) => -(320 * (count - 1)); - [0, Math.min(0, -(320 * (PROJECT_COUNT - 1)))], + [0, Math.min(0, calculateScrollOffset(PROJECT_COUNT))],
34-34
: 하드코딩된 값 상수화 필요
mt-[32rem]
와h-[320rem]
과 같은 하드코딩된 값들은 유지보수를 어렵게 만듭니다.+ const SECTION_MARGIN_TOP = '32rem'; + const SECTION_HEIGHT = '320rem'; - className="mt-[32rem] h-[320rem] px-8" + className={`mt-[${SECTION_MARGIN_TOP}] h-[${SECTION_HEIGHT}] px-8`}src/app/_data/skill.ts (1)
78-78
: 상태 관리 라이브러리 사용 경험 구체화 필요각 상태 관리 라이브러리의 사용 경험을 더 구체적으로 설명하면 좋을 것 같습니다.
- '상태 관리 라이브러리로 <b>Recoil, Zustand, Tanstack Query</b> 등을 사용한 경험이 있습니다.', + '상태 관리 라이브러리 경험: <b>Recoil</b>(전역 상태 관리), <b>Zustand</b>(상태 지속성), <b>Tanstack Query</b>(서버 상태 관리)'src/app/_sections/ProjectsSection/Project.tsx (1)
19-25
: 이미지 최적화 필요Next.js Image 컴포넌트 사용 시 다음 사항들을 고려해주세요:
height
속성에 0 대신 실제 값 지정- 반응형 이미지를 위한
sizes
속성 추가- 이미지 품질 최적화를 위한
quality
속성 설정<Image width={60} - height={0} + height={60} + sizes="60px" + quality={75} src={`/image/projects/${id}.png`} alt={title} className="h-auto duration-100 group-hover/project:scale-125" />src/app/_data/experience.ts (1)
1-9
: 인터페이스 타입 제약 추가 필요
TExperience
인터페이스의 배열 타입들에 대해 최소 길이 제약을 추가하면 좋을 것 같습니다.export interface TExperience { title: string; subtitle: string; duration: [Date, Date]; description?: string; - activities: string[]; - achievements: string[]; + activities: [string, ...string[]]; // 최소 1개 이상 + achievements: [string, ...string[]]; // 최소 1개 이상 links?: { text: string; url: string }[]; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (18)
package-lock.json
is excluded by!**/package-lock.json
public/image/projects/chat-chat.png
is excluded by!**/*.png
public/image/projects/culture-train.png
is excluded by!**/*.png
public/image/projects/egomogo.png
is excluded by!**/*.png
public/image/projects/liberty-52.png
is excluded by!**/*.png
public/image/projects/movie-movie.png
is excluded by!**/*.png
public/image/projects/oosie.png
is excluded by!**/*.png
public/image/projects/portfolio-2.png
is excluded by!**/*.png
public/image/projects/searchright.png
is excluded by!**/*.png
public/image/skills/css.png
is excluded by!**/*.png
public/image/skills/javascript.png
is excluded by!**/*.png
public/image/skills/node.png
is excluded by!**/*.png
public/image/skills/styled.png
is excluded by!**/*.png
public/image/skills/supabase.png
is excluded by!**/*.png
public/image/skills/tailwind.png
is excluded by!**/*.png
public/image/skills/tanstack-query.png
is excluded by!**/*.png
public/image/skills/typescript.png
is excluded by!**/*.png
public/image/skills/zustand.png
is excluded by!**/*.png
📒 Files selected for processing (36)
README.md
(1 hunks)package.json
(1 hunks)src/app/_components/Checkbox/Checkbox.tsx
(1 hunks)src/app/_components/Header/HeaderNav.tsx
(1 hunks)src/app/_components/Header/HeaderProgress.tsx
(1 hunks)src/app/_components/SlideInView/SlideInView.tsx
(1 hunks)src/app/_data/experience.ts
(1 hunks)src/app/_data/project.ts
(1 hunks)src/app/_data/skill.ts
(1 hunks)src/app/_sections/ContactSection/ContactSection.tsx
(1 hunks)src/app/_sections/ExperiencesSection/Experience.tsx
(1 hunks)src/app/_sections/ExperiencesSection/ExperiencesSection.tsx
(1 hunks)src/app/_sections/IntroSection/IntroSection.tsx
(1 hunks)src/app/_sections/IntroSection/WaveIcon.tsx
(1 hunks)src/app/_sections/ProjectsSection/Project.tsx
(1 hunks)src/app/_sections/ProjectsSection/ProjectsSection.tsx
(1 hunks)src/app/_sections/SectionWatcher.tsx
(1 hunks)src/app/_sections/SkillsSection/Skill.tsx
(2 hunks)src/app/_sections/SkillsSection/SkillsSection.tsx
(1 hunks)src/app/globals.css
(1 hunks)src/app/page.tsx
(1 hunks)src/components/Header/HeaderProgress.tsx
(0 hunks)src/components/Sections/ContactSection/ContactSection.tsx
(0 hunks)src/components/Sections/ExperiencesSection/Experience.tsx
(0 hunks)src/components/Sections/ProjectsSection/ProjectsSection.tsx
(0 hunks)src/components/Sections/SectionWrapper.tsx
(0 hunks)src/components/Sections/SkillsSection/SkillsSection.tsx
(0 hunks)src/components/SlideInView/SlideInView.tsx
(0 hunks)src/constants/section.ts
(0 hunks)src/data/experience.ts
(0 hunks)src/data/skill.ts
(0 hunks)src/hooks/useIntersection.ts
(0 hunks)src/hooks/useScrollProgress.ts
(0 hunks)src/hooks/useThrottle.ts
(0 hunks)src/stores/useActiveSectionIdStore.ts
(1 hunks)tailwind.config.ts
(1 hunks)
💤 Files with no reviewable changes (13)
- src/constants/section.ts
- src/data/skill.ts
- src/components/Sections/SectionWrapper.tsx
- src/components/Sections/ContactSection/ContactSection.tsx
- src/data/experience.ts
- src/hooks/useScrollProgress.ts
- src/components/SlideInView/SlideInView.tsx
- src/components/Header/HeaderProgress.tsx
- src/components/Sections/SkillsSection/SkillsSection.tsx
- src/components/Sections/ExperiencesSection/Experience.tsx
- src/hooks/useThrottle.ts
- src/components/Sections/ProjectsSection/ProjectsSection.tsx
- src/hooks/useIntersection.ts
✅ Files skipped from review due to trivial changes (1)
- src/app/page.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
src/app/_sections/ExperiencesSection/Experience.tsx
[error] 51-51: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 63-63: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
src/app/_sections/SkillsSection/Skill.tsx
[error] 26-26: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
🪛 markdownlint-cli2 (0.17.2)
README.md
15-15: Images should have alternate text (alt text)
null
(MD045, no-alt-text)
🔇 Additional comments (10)
src/app/globals.css (2)
9-11
: body 요소의 스크롤바 제거 스타일 적용
새롭게 추가된body { -ms-overflow-style: none; }
구문은 IE 및 구형 브라우저에서 스크롤바를 감추어, 모션 라이브러리 도입에 따른 깔끔한 UI 제공에 기여합니다.
12-14
: WebKit 브라우저 스크롤바 숨김 처리
body::-webkit-scrollbar { display: none; }
를 통해 Chrome, Safari 등 WebKit 기반 브라우저에서 스크롤바를 완전히 숨기는 방식이 효과적입니다. 이 변경은 불필요한 UI 요소를 제거하여 사용자 경험을 개선할 수 있습니다.src/app/_components/SlideInView/SlideInView.tsx (1)
5-7
: Props 인터페이스 구조가 명확합니다.delay prop의 타입이 적절하게 정의되어 있습니다.
src/app/_sections/ExperiencesSection/ExperiencesSection.tsx (2)
1-3
: import 경로가 새로운 디렉토리 구조를 반영합니다.app 디렉토리로의 마이그레이션이 잘 이루어졌습니다.
8-9
: 반응형 디자인 구현이 개선되었습니다.gap과 padding 값의 조정으로 모바일/태블릿 환경에서의 레이아웃이 개선되었습니다.
src/stores/useActiveSectionIdStore.ts (1)
3-8
: 섹션 ID 타입 정의가 명확합니다.유니온 타입을 사용하여 가능한 섹션 ID 값을 제한한 것이 좋습니다.
src/app/_sections/SkillsSection/SkillsSection.tsx (1)
9-10
: 반응형 그리드 레이아웃이 잘 구현되어 있습니다.배경 효과와 함께 스킬 섹션의 시각적 구조가 잘 설계되었습니다.
src/app/_data/project.ts (1)
3-11
: 인터페이스 구조가 잘 설계되었습니다!프로젝트 데이터를 위한 인터페이스가 명확하게 정의되어 있으며, 필요한 모든 필드가 포함되어 있습니다. 특히
description
을 string 또는 string[] 타입으로 유연하게 정의한 점이 좋습니다.src/app/_sections/ExperiencesSection/Experience.tsx (1)
6-87
: 컴포넌트 구조가 체계적으로 잘 구성되었습니다!
- 타입스크립트 인터페이스를 잘 활용했습니다
- 조건부 렌더링이 깔끔하게 처리되었습니다
- Tailwind 클래스를 활용한 스타일링이 일관성 있게 적용되었습니다
🧰 Tools
🪛 Biome (1.9.4)
[error] 51-51: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 63-63: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
package.json (1)
12-12
:✅ Verification successful
motion 라이브러리 버전 호환성 확인 필요
motion 라이브러리의 버전(12.4.2)이 React 19 및 Next.js 15.1.5와 호환되는지 확인해주세요.
🌐 Web query:
Is Framer Motion v12.4.2 compatible with React 19 and Next.js 15?
💡 Result:
Framer Motion v12.4.2 (now rebranded as Motion for React) is compatible with React 19 and Next.js 15 when using the updated
motion
package instead offramer-motion
. Here's what you need to know:Key Compatibility Points
Package Renaming
- Replace
framer-motion
withmotion
in your dependencies[1][3].- Use imports from
"motion/react"
instead of"framer-motion"
[1][3]:npm uninstall framer-motion npm install motionReact 19 Support
- Motion v12+ aligns with React 19’s changes (e.g., ref handling in props)[5][9].
- Next.js 15’s App Router uses React 19 RC by default[2][4], but ensure third-party libraries like Motion are updated to avoid conflicts[6][7].
Next.js Compatibility
- Next.js 15 supports both React 18 (Pages Router) and React 19 (App Router)[2][4].
- For server components, use
motion/react-client
imports[5]:import * as motion from "motion/react-client";Common Issues & Fixes
- Peer Dependency Conflicts: Earlier alphas (e.g.,
12.0.0-alpha.0
) had issues with React 19 due to hardcoded peer dependencies on React 18[6][7]. This was resolved in stable releases like v12.4.2.- Testing: Update Jest tests to await microtask renders introduced in React 19[1].
Example Integration
// Client Component import { motion } from "motion/react"; export default function AnimatedComponent() { return ( <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 0.5 }} /> ); }For server components, use a client-side wrapper or dynamic imports[8].
Summary: Use
motion@12.4.2
withnext@15
andreact@19
by following updated import paths and ensuring dependencies are cleanly upgraded[1][3][9].Citations:
- 1: https://motion.dev/docs/react-upgrade-guide
- 2: https://nextjs.org/blog/next-15
- 3: https://www.npmjs.com/package/framer-motion
- 4: https://nextjs.org/blog/next-15-rc
- 5: https://motion.dev/docs/react-motion-component
- 6: https://community.fly.io/t/cant-launch-a-next-js-15-rc-react-19-rc-app/20915
- 7: [BUG] Incompatible with React 19 motiondivision/motion#2668
- 8: https://www.youtube.com/watch?v=T90QUHosXIU
- 9: https://www.framer.community/c/developers/framer-motion-v12-alpha-for-react-19-rc
- 10: https://answers.netlify.com/t/gatsby-site-deployment-failure-no-such-file-or-directory/79110
모션 라이브러리 버전 호환성 검증 완료
현재
"motion": "^12.4.2"
는 최신 업데이트에 따라 React 19 및 Next.js 15와 호환되는 것으로 확인되었습니다. 다만, 패키지 이름이 기존의framer-motion
에서motion
으로 변경되었으므로, 올바른 import 경로(예: 클라이언트 컴포넌트의 경우"motion/react"
, 서버 컴포넌트의 경우"motion/react-client"
)를 사용하고 있는지 다시 한번 확인해 주세요.
- 확인 사항
- 기존
framer-motion
관련 import가 남아있지 않은지.- 클라이언트와 서버 컴포넌트에서 각각 올바른 모듈(import 경로)을 사용 중인지.
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: 0
♻️ Duplicate comments (2)
src/app/_sections/ProjectsSection/Project.tsx (1)
51-56
: 🛠️ Refactor suggestion툴팁 접근성 개선이 필요합니다.
현재 툴팁 구현은 스크린 리더 사용자에게 접근이 어려울 수 있습니다.
<span className="hover absolute left-1/2 top-[140%] hidden -translate-x-1/2 whitespace-nowrap rounded-sm bg-black/50 px-2 py-1 text-white group-hover/skill:block" - aria-label={`사용된 기술: ${skill}`} + role="tooltip" + aria-label={`사용된 기술: ${skill}`} > {skill} </span>src/app/_data/project.ts (1)
43-43
:⚠️ Potential issue프로젝트 날짜를 현재 시점으로 수정해주세요.
일부 프로젝트의 날짜가 미래로 설정되어 있습니다. 포트폴리오의 신뢰성을 위해 현재 시점(2024년 2월)을 기준으로 날짜를 수정하는 것이 좋겠습니다.
Also applies to: 52-52, 60-60, 69-69, 77-77, 91-91
🧹 Nitpick comments (4)
src/app/_sections/ProjectsSection/Project.tsx (2)
19-25
: 이미지 최적화 개선이 필요합니다.Next.js Image 컴포넌트 사용 시 다음 사항들을 개선하면 좋겠습니다:
height
속성에 0 대신 실제 값을 지정- 이미지 품질과 로딩 성능을 위해
quality
와priority
속성 추가 고려<Image width={60} - height={0} + height={60} src={`/image/projects/${id}.png`} alt={title} + quality={90} + priority={true} className="h-auto duration-100 group-hover/project:scale-125" />
28-36
: 설명 텍스트의 높이 제한이 UX에 영향을 줄 수 있습니다.
h-12
클래스로 인해 설명 텍스트가 잘릴 수 있습니다. 다음과 같은 개선을 제안합니다:
- 높이 제한 제거
- 말줄임표(...) 처리
- 또는 동적 높이 조정
-<p className="mx-4 mb-5 h-12 text-center text-lg"> +<p className="mx-4 mb-5 text-center text-lg line-clamp-2">src/app/_data/project.ts (2)
18-18
: 날짜 형식을 일관성 있게 수정해주세요.날짜 문자열 형식이 일관되지 않습니다. YYYY.MM 형식으로 통일하는 것이 좋겠습니다.
- duration: [new Date('2023.03'), new Date('2023.12')], + duration: [new Date('2023.03.01'), new Date('2023.12.31')],Also applies to: 26-26, 34-34
3-11
: 타입 정의 개선이 필요합니다.더 엄격한 타입 체크를 위해 다음 개선사항을 제안합니다:
id
에 가능한 값들을 유니온 타입으로 정의duration
타입을 커스텀 타입으로 분리하여 재사용성 확보+type ProjectId = 'liberty-52' | 'egomogo' | 'chat-chat' | 'movie-movie' | 'culture-train' | 'oosie' | 'searchright' | 'portfolio-2'; +type ProjectDuration = [Date, Date]; export interface TProject { - id: string; + id: ProjectId; title: string; description: string | string[]; - duration: [Date, Date]; + duration: ProjectDuration; mainSkills: TSkillImgFileName[]; isMain: boolean; bgDark?: boolean; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/app/_data/project.ts
(1 hunks)src/app/_sections/ProjectsSection/Project.tsx
(1 hunks)
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
♻️ Duplicate comments (2)
src/app/_sections/SkillsSection/Skill.tsx (1)
25-27
:⚠️ Potential issuedangerouslySetInnerHTML 사용에 대한 보안 경고
HTML 콘텐츠를 안전하게 렌더링하기 위해 DOMPurify와 같은 sanitization 라이브러리를 사용하는 것을 권장드립니다. XSS 공격 위험을 방지하기 위해 이 부분을 수정해 주시기 바랍니다.
🧰 Tools
🪛 Biome (1.9.4)
[error] 26-26: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
src/app/_sections/ExperiencesSection/Experience.tsx (1)
57-57
:⚠️ Potential issuedangerouslySetInnerHTML 사용에 대한 보안 위험
dangerouslySetInnerHTML
의 사용은 XSS 공격에 취약할 수 있습니다. HTML 콘텐츠를 안전하게 렌더링하기 위해 다음과 같은 대안을 고려해보세요:
- DOMPurify 라이브러리 사용
- 마크다운 렌더러 사용 (예: react-markdown)
- 허용된 HTML 태그만 파싱하는 커스텀 컴포넌트 구현
Also applies to: 69-69
🧰 Tools
🪛 Biome (1.9.4)
[error] 57-57: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
🧹 Nitpick comments (4)
src/app/_sections/SkillsSection/Skill.tsx (1)
15-15
: 이미지 대체 텍스트를 더 설명적으로 개선하세요.현재 alt 텍스트는 파일 이름에 "아이콘"을 붙인 형태입니다. 스크린 리더 사용자를 위해 기술의 실제 이름을 사용하는 것이 더 도움이 될 것 같습니다.
예시:
-alt={`${imgFileName} 아이콘`} +alt={`${title} 기술 아이콘`}src/app/_sections/ProjectsSection/Project.tsx (1)
19-25
: 이미지 대체 텍스트 개선 필요현재 alt 텍스트는 단순히 "로고"만 언급하고 있습니다. 스크린 리더 사용자를 위해 더 자세한 설명을 제공하면 좋을 것 같습니다.
- alt={`${title} 로고`} + alt={`${title} 프로젝트 로고 이미지`}src/app/_sections/ExperiencesSection/Experience.tsx (1)
74-90
: 링크 섹션의 접근성 개선이 필요합니다.링크의 목적이나 대상을 명확히 하기 위해
aria-label
을 추가하는 것이 좋습니다.다음과 같이 수정해보세요:
- <Link href={link.url}>{link.text}</Link> + <Link + href={link.url} + aria-label={`${link.text} - 새 탭에서 열기`} + target="_blank" + rel="noopener noreferrer" + > + {link.text} + </Link>src/app/_sections/SectionWatcher.tsx (1)
24-34
: viewport margin을 props로 설정하는 것을 고려해보세요현재 viewport margin이 하드코딩되어 있어 재사용성이 제한될 수 있습니다. 이를 props로 받아 더 유연하게 사용할 수 있도록 개선하는 것이 좋겠습니다.
function SectionWatcher({ sectionId, children, className, + viewportMargin = '0px 0px -10%', -}: { sectionId: TSectionId } & ComponentProps<'section'>) { +}: { sectionId: TSectionId; viewportMargin?: string } & ComponentProps<'section'>) { // ... return ( <motion.section id={sectionId} className={className} onViewportEnter={onViewportEnter} onViewportLeave={onViewportLeave} - viewport={{ margin: '0px 0px -10%' }} + viewport={{ margin: viewportMargin }} > {children} </motion.section> ); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
public/image/skills/styled-component.png
is excluded by!**/*.png
public/image/skills/tailwind-css.png
is excluded by!**/*.png
📒 Files selected for processing (10)
src/app/_data/experience.ts
(1 hunks)src/app/_sections/ExperiencesSection/Experience.tsx
(1 hunks)src/app/_sections/ExperiencesSection/ExperiencesSection.tsx
(1 hunks)src/app/_sections/ProjectsSection/Project.tsx
(1 hunks)src/app/_sections/ProjectsSection/ProjectsSection.tsx
(1 hunks)src/app/_sections/SectionWatcher.tsx
(1 hunks)src/app/_sections/SkillsSection/Skill.tsx
(2 hunks)src/app/_sections/SkillsSection/SkillsSection.tsx
(1 hunks)src/app/layout.tsx
(1 hunks)src/utils/util.ts
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- src/app/layout.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
- src/app/_sections/SkillsSection/SkillsSection.tsx
- src/app/_data/experience.ts
- src/app/_sections/ExperiencesSection/ExperiencesSection.tsx
- src/app/_sections/ProjectsSection/ProjectsSection.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
src/app/_sections/ExperiencesSection/Experience.tsx
[error] 57-57: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 69-69: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
src/app/_sections/SkillsSection/Skill.tsx
[error] 26-26: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
🔇 Additional comments (10)
src/app/_sections/SkillsSection/Skill.tsx (1)
1-1
: 타입 변경이 일관성 있게 적용되었습니다!
TSkillContent
에서TSkill
로의 타입 변경이 import문과 함수 매개변수에 모두 올바르게 반영되었습니다.Also applies to: 7-7
src/app/_sections/ProjectsSection/Project.tsx (4)
1-10
: 코드가 깔끔하고 잘 구성되어 있습니다!타입스크립트를 활용한 props 정의와 필요한 컴포넌트들의 import가 잘 되어있습니다.
28-36
: 설명 텍스트 표시 방식 검토 필요
h-12
로 고정된 높이와line-clamp-2
를 사용하고 있어, 긴 설명 텍스트가 잘릴 수 있습니다. 사용자가 전체 내용을 확인할 수 있는 방법을 고려해보세요.다음과 같은 대안을 고려해볼 수 있습니다:
- 툴팁으로 전체 내용 표시
- 호버 시 전체 내용 표시
- "더 보기" 버튼 추가
37-44
: 접근성을 고려한 날짜 표시 구현이 잘 되어있습니다!aria-label을 사용한 날짜 정보 전달과 장식용 구분자의 aria-hidden 처리가 적절합니다.
54-60
: 이전 리뷰의 접근성 개선 사항이 잘 반영되었습니다!툴팁에 role="tooltip"과 aria-label을 추가하여 스크린 리더 사용자의 접근성이 개선되었습니다.
src/utils/util.ts (1)
7-8
: LGTM! 접근성을 고려한 좋은 구현입니다.날짜를 한국어 형식으로 변환하여 스크린 리더 사용자에게 더 자연스러운 경험을 제공합니다.
src/app/_sections/ExperiencesSection/Experience.tsx (2)
22-29
: 접근성이 잘 고려된 구현입니다!날짜 범위에 대한 aria-label이 적절하게 구현되어 있으며, 구분자("-")에
aria-hidden
을 적용한 것이 좋습니다.
30-41
: 이미지의 접근성 처리가 잘 되어있습니다.장식용 별 이미지에
aria-hidden
을 적용한 것이 적절합니다. 또한 시맨틱 HTML을 사용하여 제목의 계층 구조를 잘 표현하였습니다.src/app/_sections/SectionWatcher.tsx (2)
8-15
: 깔끔한 props 및 hooks 구현입니다!타입 정의와 상태 관리가 잘 구현되어 있습니다.
16-22
: 이벤트 핸들러가 깔끔하게 구현되었습니다!이전 리뷰 코멘트에서 지적된 console.log 문이 제거되어 있고, 이벤트 핸들러가 간결하게 구현되어 있습니다.
Summary by CodeRabbit