Skip to content

refactor/#26: 공통된 padding 설정 컴포넌트화#27

Merged
yungu0010 merged 5 commits intodevelopfrom
refactor/#26
Apr 22, 2026
Merged

refactor/#26: 공통된 padding 설정 컴포넌트화#27
yungu0010 merged 5 commits intodevelopfrom
refactor/#26

Conversation

@yungu0010
Copy link
Copy Markdown
Member

Work Description ✏️

  • 작업 설명을 적어주세요.

PR Point 📸

Related Issue 🚀

Work Description ✏️

  • FieldSection 컴포넌트 추출 (common/ui/, paddingTop: 24px / paddingBottom: 12px)
  • StepLayout contentSection 좌우 패딩 20px → 28px 통일, textAlign: left 추가
  • UserInfoPage · SprintCodePage · MvpPage · PeerCommentStepTemplateFieldSection 적용
  • 각 입력 블록을 개별 FieldSection으로 분리해 섹션 간 수직 여백 통일
  • PeerCommentStepTemplateheadingBlock div 및 globalStyle 제거 → FieldSection 교체
  • SprintCodeInput 자체 패딩 제거 (FieldSection에 위임)

PR Point 📸

없음

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 22, 2026

Warning

Rate limit exceeded

@yungu0010 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 51 minutes and 48 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 51 minutes and 48 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2422f3da-eb8a-4346-95d4-2a4f176b5963

📥 Commits

Reviewing files that changed from the base of the PR and between 862de22 and fceb0aa.

📒 Files selected for processing (2)
  • CLAUDE.md
  • src/pages/MvpPage.tsx

📋 개요

새로운 FieldSection 레이아웃 컴포넌트를 도입하고 여러 페이지에서 일관되게 사용하도록 리팩토링했습니다. 기존 컨테이너 스타일을 제거하고 패딩을 조정하여 레이아웃 구조를 정규화했습니다.

📝 변경 사항

응집 그룹 / 파일 요약
FieldSection 컴포넌트 신규 추가
src/components/common/ui/FieldSection.tsx, src/components/common/ui/FieldSection.css.ts, src/components/index.ts
새로운 FieldSection React 컴포넌트를 도입했습니다. 플렉스박스 컬럼 레이아웃(paddingTop: 24, paddingBottom: 12)을 적용하며, 공개 API를 통해 내보냅니다.
문서 및 메타데이터 업데이트
CLAUDE.md
UI 컴포넌트 목록에 FieldSection을 추가하고, Block/Section 명명 규칙 문서를 확장했습니다.
레이아웃 패딩 조정
src/components/common/layout/StepLayout.css.ts, src/components/common/ui/ProgressBar.css.ts, src/components/sprint-code/SprintCodeInput.css.ts
contentSectioncontainer 패딩을 업데이트하고 텍스트 정렬을 조정했습니다. 불필요한 패딩 선언을 제거했습니다.
PeerCommentStepTemplate 페이지 리팩토링
src/components/peer-comment/PeerCommentStepTemplate.css.ts, src/components/peer-comment/PeerCommentStepTemplate.tsx
기존 headingBlock 스타일과 globalStyle 규칙을 제거하고 FieldSection 래퍼로 대체했습니다. 새로운 noticeText 스타일을 도입했습니다.
MvpPage 페이지 리팩토링
src/pages/MvpPage.css.ts, src/pages/MvpPage.tsx
기존 bodyfields 스타일을 제거하고 여러 FieldSection 블록으로 레이아웃을 재구성했습니다. 선택된 멤버 렌더링 방식을 chipList 구조로 변경했습니다.
SprintCodePage 페이지 리팩토링
src/pages/SprintCodePage.tsx
ContentHeadingSprintCodeInput을 각각 FieldSection 컴포넌트로 래핑했습니다.
UserInfoPage 페이지 리팩토링
src/pages/UserInfoPage.css.ts, src/pages/UserInfoPage.tsx
기존 bodyinputWrapper 스타일을 제거하고 noticeText 스타일을 도입했습니다. 폼 UI를 개별 FieldSection 블록으로 분리했습니다.

🎯 예상 코드 리뷰 노력

🎯 3 (중간) | ⏱️ ~25분

🔗 관련 가능성이 있는 PR

🐰 축제 시

🌿 새 필드 섹션 등장, 패딩 정렬해 놓고 🎨
페이지마다 예쁜 컴포넌트를 배치하니
레이아웃 공통화로 코드가 깔끔해졌어요! 🐇✨
반복되던 스타일 제거하고
일관된 여백으로 우아함을 더했습니다 🎭

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 FieldSection 컴포넌트 추출과 공통 padding 설정 컴포넌트화라는 주요 변경사항을 명확하게 반영하고 있습니다.
Description check ✅ Passed PR 설명에는 관련 이슈, 작업 설명, PR Point가 포함되어 있으며, 주요 변경사항(FieldSection 추출, StepLayout 패딩 통일, 다중 페이지 적용)이 상세히 기술되어 있습니다.
Linked Issues check ✅ Passed PR은 이슈 #26의 목표인 '공통된 padding 영역 컴포넌트화'를 완전히 충족합니다. FieldSection 컴포넌트를 추출하고 여러 페이지에 일관되게 적용했습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 공통 padding 컴포넌트화 목표에 부합하며, 범위를 벗어난 변경은 없습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/#26

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (2)
src/pages/MvpPage.tsx (1)

21-23: 검색 필터가 대소문자를 구분합니다.

m.name.includes(searchQuery)는 대소문자를 구분합니다. 한글 사용이 주라면 영향이 작지만, 영문/혼합 이름을 고려하면 정규화 후 비교하는 것이 안전합니다.

♻️ 제안
-  const filteredMembers = searchQuery
-    ? peerMembers.filter((m) => m.name.includes(searchQuery))
-    : [];
+  const filteredMembers = searchQuery
+    ? peerMembers.filter((m) => m.name.toLowerCase().includes(searchQuery.toLowerCase()))
+    : [];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/MvpPage.tsx` around lines 21 - 23, filteredMembers uses a
case-sensitive includes check (m.name.includes(searchQuery)), so normalize both
sides before comparing: convert searchQuery and m.name to a consistent case
(e.g., .toLowerCase()) and trim whitespace, and guard against undefined names
(e.g., m.name || '') so the filter on peerMembers returns matches
case-insensitively; update the filter in the filteredMembers computation to use
the normalized values.
src/components/common/ui/FieldSection.tsx (1)

8-10: 선택) 시맨틱 태그 고려.

컴포넌트명이 Section이고 그룹 영역을 나타내므로 <div> 대신 <section> 사용을 고려해볼 수 있습니다. 다만 랜드마크 의미가 없다면 현재 <div>도 무방합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/common/ui/FieldSection.tsx` around lines 8 - 10, The
FieldSection component currently renders a <div>; since the component name and
purpose indicate a grouped section, change the root element in the FieldSection
function to a semantic <section> (preserving className={styles.container} and
children) so the component uses proper landmark semantics; leave it as <div>
only if you intentionally do not want a landmark.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/common/ui/FieldSection.css.ts`:
- Around line 3-8: The CSS for FieldSection is missing the gap property
described in the PR; update the exported container style (container in
src/components/common/ui/FieldSection.css.ts) to include gap: 28 (e.g., gap: 28)
so children like ContentHeading and <p> have the intended spacing, or if removal
was intentional, update the PR description to reflect the change instead of
adding the gap.

In `@src/components/peer-comment/PeerCommentStepTemplate.tsx`:
- Around line 63-66: FieldSection currently lacks spacing between its children
causing ContentHeading and the paragraph with class noticeText to run together;
update the FieldSection component styles (FieldSection.css.ts) to include a gap:
28px (or gap: 28) so all children (including ContentHeading and the
p.noticeText) receive consistent vertical spacing across usages, and remove any
per-instance margin hacks from PeerCommentStepTemplate; target the FieldSection
style definition rather than changing individual consumers.

In `@src/pages/MvpPage.css.ts`:
- Line 62: boxShadow in MvpPage.css.ts currently uses a hardcoded color 'rgba(0,
0, 0, 0.4)'; replace this hardcoded alpha color with a design-token-based value
once the design team provides a shadow token: remove the literal rgba in the
boxShadow declaration, use the shadow token (e.g., a new token name like
colors.shadow.* or theme.shadow.*) or a named placeholder constant, and add a
short TODO comment referencing the design token decision so it's easy to swap in
the final token when available; target the boxShadow property in MvpPage.css.ts
for this change.

In `@src/pages/MvpPage.tsx`:
- Line 88: Replace the inline style usage on IconXCircle and IconUser in
MvpPage.tsx with class names from a vanilla-extract stylesheet: move the
width/height/color properties into MvpPage.css.ts (create/update style tokens
such as iconSmall or iconDefault and color tokens used for colors.gray50),
export the class names, then apply those classes to the icon components via
className in MvpPage.tsx (remove style={{...}}). Ensure both occurrences (around
lines where IconXCircle and IconUser are used) use the new vanilla-extract
classes.
- Around line 71-110: The custom search + dropdown lacks ARIA roles and keyboard
support; replace it by using the existing accessible components from
`@sopt-makers/ui` (SearchField or Select) instead of the manual input/list logic:
wire the component's value to searchQuery, map filteredMembers to the
component's options, forward selection events to handleSelectMember, and remove
the custom dropdown rendering (the block using filteredMembers.map and the input
with clearButton) so the library component manages role="combobox",
aria-expanded, keyboard navigation, and aria-activedescendant for you.

---

Nitpick comments:
In `@src/components/common/ui/FieldSection.tsx`:
- Around line 8-10: The FieldSection component currently renders a <div>; since
the component name and purpose indicate a grouped section, change the root
element in the FieldSection function to a semantic <section> (preserving
className={styles.container} and children) so the component uses proper landmark
semantics; leave it as <div> only if you intentionally do not want a landmark.

In `@src/pages/MvpPage.tsx`:
- Around line 21-23: filteredMembers uses a case-sensitive includes check
(m.name.includes(searchQuery)), so normalize both sides before comparing:
convert searchQuery and m.name to a consistent case (e.g., .toLowerCase()) and
trim whitespace, and guard against undefined names (e.g., m.name || '') so the
filter on peerMembers returns matches case-insensitively; update the filter in
the filteredMembers computation to use the normalized values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8f6f929c-30ee-4526-8913-8a2a37b82c23

📥 Commits

Reviewing files that changed from the base of the PR and between e1925cf and 7499334.

📒 Files selected for processing (18)
  • CLAUDE.md
  • src/App.tsx
  • src/components/common/layout/StepLayout.css.ts
  • src/components/common/ui/FieldSection.css.ts
  • src/components/common/ui/FieldSection.tsx
  • src/components/common/ui/ProgressBar.css.ts
  • src/components/index.ts
  • src/components/peer-comment/PeerCommentStepTemplate.css.ts
  • src/components/peer-comment/PeerCommentStepTemplate.tsx
  • src/components/sprint-code/SprintCodeInput.css.ts
  • src/components/sprint-code/SprintCodeInput.tsx
  • src/pages/ClosingPage.tsx
  • src/pages/ContinueCommentPage.tsx
  • src/pages/MvpPage.css.ts
  • src/pages/MvpPage.tsx
  • src/pages/SprintCodePage.tsx
  • src/pages/UserInfoPage.css.ts
  • src/pages/UserInfoPage.tsx
💤 Files with no reviewable changes (2)
  • src/components/sprint-code/SprintCodeInput.css.ts
  • src/pages/ClosingPage.tsx

Comment on lines +3 to +8
export const container = style({
display: 'flex',
flexDirection: 'column',
paddingTop: 24,
paddingBottom: 12,
});
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Apr 22, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

PR 설명의 gap: 28px이 누락되어 있습니다.

PR 본문에는 FieldSectionpaddingTop: 24, paddingBottom: 12, gap: 28을 가진다고 기술되어 있으나 실제 스타일에는 gap이 정의되어 있지 않습니다. 의도적으로 제거한 것이 아니라면 추가가 필요하고, 의도적이라면 PR 설명을 수정해 주세요. UserInfoPage처럼 ContentHeading<p>를 같은 섹션에 나란히 두는 케이스에서는 자식 간 간격이 없어 시각적으로 붙어 보일 수 있습니다.

♻️ 제안
 export const container = style({
   display: 'flex',
   flexDirection: 'column',
+  gap: 28,
   paddingTop: 24,
   paddingBottom: 12,
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const container = style({
display: 'flex',
flexDirection: 'column',
paddingTop: 24,
paddingBottom: 12,
});
export const container = style({
display: 'flex',
flexDirection: 'column',
gap: 28,
paddingTop: 24,
paddingBottom: 12,
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/common/ui/FieldSection.css.ts` around lines 3 - 8, The CSS for
FieldSection is missing the gap property described in the PR; update the
exported container style (container in
src/components/common/ui/FieldSection.css.ts) to include gap: 28 (e.g., gap: 28)
so children like ContentHeading and <p> have the intended spacing, or if removal
was intentional, update the PR description to reflect the change instead of
adding the gap.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

FieldSection 간격이 0이 되면서 gap이 불필요해진게 맞아

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@yungu0010, 의도적인 변경이었군요! 설명 감사합니다. 다만 PR 설명에 아직 gap: 28이 언급되어 있을 수 있으니, 혼란을 줄이기 위해 PR 본문도 간략히 수정해 두시면 좋을 것 같습니다.


✏️ Learnings added
Learnt from: yungu0010
Repo: sopt-makers/hear-your-voice PR: 27
File: src/components/common/ui/FieldSection.css.ts:3-8
Timestamp: 2026-04-22T12:09:05.575Z
Learning: In `src/components/common/ui/FieldSection.css.ts`, the `gap` property is intentionally omitted from the `container` style. The spacing between child elements became 0, making `gap` unnecessary. Do not flag its absence as a missing style.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: CR
Repo: sopt-makers/hear-your-voice PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-22T08:56:59.118Z
Learning: Applies to **/*.css.ts : Use vanilla-extract (`*.css.ts`) for styling — do not use inline styles or CSS modules (`.module.css`)

Learnt from: CR
Repo: sopt-makers/hear-your-voice PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-22T08:56:59.118Z
Learning: Applies to src/components/**/*Field.tsx : Form field components with labels and descriptions must have postfix `Field` (e.g., `SelectField`, `InputField`)

Comment on lines +63 to +66
<FieldSection>
<ContentHeading title={title} description={description} />
<p>해당 코멘트는 무기명으로 전달되어요.</p>
</div>
<p className={styles.noticeText}>해당 코멘트는 무기명으로 전달되어요.</p>
</FieldSection>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: FieldSection 스타일과 사용처를 확인해 내부 gap이 공통 컴포넌트에서 제공되는지 검증합니다.
# Expect: FieldSection.css.ts에 gap: 28이 있거나, 각 사용처에서 별도 간격을 명시해야 합니다.

fd -i 'FieldSection\.(tsx|css\.ts)$' -x sed -n '1,120p' {}
rg -n -C2 '<FieldSection>|gap\s*:' --type ts --type tsx

Repository: sopt-makers/hear-your-voice

Length of output: 577


🏁 Script executed:

# noticeText 스타일 확인
rg -n "noticeText" src/components/peer-comment/ -A5 -B2

# PeerCommentStepTemplate.tsx의 전체 스타일 파일 확인
fd "PeerCommentStepTemplate" --type f -e css.ts -e tsx | head -5 | xargs cat

# FieldSection 다른 사용처 확인
rg "<FieldSection>" --type tsx -B2 -A2 | head -50

Repository: sopt-makers/hear-your-voice

Length of output: 4568


🏁 Script executed:

# ContentHeading 스타일 확인
rg "ContentHeading" src/components/common/ui/ -l | xargs cat

# FieldSection 다른 사용처 찾기
rg "<FieldSection>" --type ts -B5 -A5

Repository: sopt-makers/hear-your-voice

Length of output: 6133


🏁 Script executed:

# ContentHeading.css.ts 전체 파일 확인
cat src/components/common/ui/ContentHeading.css.ts

Repository: sopt-makers/hear-your-voice

Length of output: 592


FieldSection 내부 자식 요소들 사이에 간격이 없어서 ContentHeading과 안내 문구가 붙을 수 있습니다.

FieldSection.css.ts에는 gap 스타일이 없고, noticeText도 상단 마진이 없어서 이 구조에서는 제목과 안내 텍스트가 직접 붙게 됩니다. FieldSectiongap: 28을 추가하여 공유 컴포넌트 차원에서 일관된 간격을 제공하는 것이 좋습니다.

수정 예시
 export const container = style({
   display: 'flex',
   flexDirection: 'column',
   paddingTop: 24,
   paddingBottom: 12,
+  gap: 28,
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/peer-comment/PeerCommentStepTemplate.tsx` around lines 63 -
66, FieldSection currently lacks spacing between its children causing
ContentHeading and the paragraph with class noticeText to run together; update
the FieldSection component styles (FieldSection.css.ts) to include a gap: 28px
(or gap: 28) so all children (including ContentHeading and the p.noticeText)
receive consistent vertical spacing across usages, and remove any per-instance
margin hacks from PeerCommentStepTemplate; target the FieldSection style
definition rather than changing individual consumers.

Comment thread src/pages/MvpPage.css.ts Outdated
overflow: 'hidden',
listStyle: 'none',
padding: 0,
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.4)',
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 기존에 사용된 shadow/rgba 토큰 패턴 확인
rg -nP 'boxShadow|rgba\(' -g '*.css.ts'

Repository: sopt-makers/hear-your-voice

Length of output: 144


🏁 Script executed:

# Check if `@sopt-makers/colors` is in package.json and locate its definition
cat package.json | grep -A 5 -B 5 "sopt-makers"

Repository: sopt-makers/hear-your-voice

Length of output: 559


🏁 Script executed:

# Search for colors or shadows exports/definitions
find . -type f -name "colors.ts" -o -name "colors.js" -o -name "index.ts" | grep -i color | head -20

Repository: sopt-makers/hear-your-voice

Length of output: 53


🏁 Script executed:

# Look for any references to shadow tokens or color imports in the codebase
rg -l '@sopt-makers/colors' --type ts --type tsx | head -10

Repository: sopt-makers/hear-your-voice

Length of output: 98


🏁 Script executed:

# Check for other CSS files to see how colors are imported and used
rg -n 'from.*@sopt-makers/colors' -g '*.css.ts' | head -20

Repository: sopt-makers/hear-your-voice

Length of output: 1511


🏁 Script executed:

# Search for all boxShadow usages in the codebase
rg 'boxShadow' -g '*.css.ts' -n

Repository: sopt-makers/hear-your-voice

Length of output: 144


🏁 Script executed:

# Check the MvpPage.css.ts file to see the full context and how colors are used
cat src/pages/MvpPage.css.ts

Repository: sopt-makers/hear-your-voice

Length of output: 2080


🌐 Web query:

@sopt-makers/colors 3.0.3 shadow tokens documentation

💡 Result:

@sopt-makers/colors 3.0.3는 SOPT Makers의 design system에서 사용되는 색상 디자인 토큰 패키지입니다. 이 패키지는 주로 색상(color) 토큰을 제공하며, shadow tokens에 대한 명시적인 문서는 발견되지 않았습니다. Shadow tokens는 별도의 패키지나 makers-design-system의 다른 부분에 있을 수 있지만, 현재 검색 결과로는 @sopt-makers/colors 패키지에 shadow tokens가 포함되어 있지 않습니다. 주요 발견사항: - 패키지 설명: "sopt-makers의 frontend repository에 사용되는 colors를 제공해요." (SOPT makers frontend repository에 사용되는 colors를 제공합니다.) - NPM 페이지에 README가 없고, dist 파일만 있으며 크기가 작음 (색상 토큰만 포함). - makers-design-system GitHub 저장소 (https://github.com/sopt-makers/makers-design-system)에서 @sopt-makers/colors가 design tokens의 일부로 언급되지만, shadow에 대한 구체적 문서는 없음. - Storybook 링크가 언급되지만, 공개된 shadow tokens 문서 URL은 확인되지 않음.

Citations:


하드코딩된 색상값(rgba(0,0,0,0.4)) 사용 — 가이드라인 위반.

@sopt-makers/colors 에는 현재 shadow 토큰이 포함되어 있지 않으므로, 디자인팀과 shadow 토큰 정의를 확정한 후 적용해 주세요.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/MvpPage.css.ts` at line 62, boxShadow in MvpPage.css.ts currently
uses a hardcoded color 'rgba(0, 0, 0, 0.4)'; replace this hardcoded alpha color
with a design-token-based value once the design team provides a shadow token:
remove the literal rgba in the boxShadow declaration, use the shadow token
(e.g., a new token name like colors.shadow.* or theme.shadow.*) or a named
placeholder constant, and add a short TODO comment referencing the design token
decision so it's easy to swap in the final token when available; target the
boxShadow property in MvpPage.css.ts for this change.

Comment thread src/pages/MvpPage.tsx
Comment on lines +71 to +110
<div className={styles.searchContainer}>
<div className={styles.inputWrapper}>
<input
className={styles.searchInput}
placeholder="멤버 검색"
value={searchQuery}
onChange={(e: ChangeEvent<HTMLInputElement>) =>
setSearchQuery(e.target.value)
}
/>
{searchQuery && (
<button
type="button"
className={styles.clearButton}
onClick={() => setSearchQuery('')}
aria-label="검색어 지우기"
>
<IconXCircle style={{ width: 20, height: 20, color: colors.gray50 }} />
</button>
)}
</div>

{searchQuery && filteredMembers.length > 0 && (
<ul className={styles.dropdown}>
{filteredMembers.map((member) => (
<li key={member.userId}>
<button
type="button"
className={styles.dropdownItem}
onClick={() => handleSelectMember(member)}
>
<span className={styles.avatarIcon} aria-hidden>
<IconUser style={{ width: 20, height: 20 }} />
</span>
<span>{member.name}</span>
</button>
</li>
))}
</ul>
)}
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Apr 22, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

@sopt-makers/ui 2.11.0 components Select SearchField combobox

💡 Result:

@sopt-makers/ui version 2.11.0 is the latest release (published Jan 17, 2026) of the Makers Design System UI component library from SOPT makers. It provides React components built with TypeScript, vanilla-extract for styling, and dependencies like Radix UI primitives. The library includes Select (V2) and SearchField components, listed under form inputs in the official repository. These are likely used together to create searchable combobox/select functionality: - SearchField: A search input component. - Select(V2): An updated selectable dropdown/combobox component. No public Storybook demo or detailed API docs were found in searches, but components are part of the monorepo https://github.com/sopt-makers/makers-design-system (last updated Feb 2026). Source code is in the packages/ui directory (not directly surfaced, but inferable from npm files and repo structure). To use in a project: npm install @sopt-makers/ui@2.11.0 Typical usage (based on standard Radix patterns, as no exact examples found): import { SearchField, Select } from '@sopt-makers/ui'; A combobox would combine SearchField for filtering with Select(V2) for options selection. Check the GitHub repo for exact implementation and stories.

Citations:


🏁 Script executed:

# Check if package.json exists and search for `@sopt-makers/ui` dependency
fd package.json | head -5 && echo "---" && rg '@sopt-makers/ui' --type json

Repository: sopt-makers/hear-your-voice

Length of output: 344


🏁 Script executed:

# Verify MvpPage.tsx exists and check the relevant lines
fd MvpPage.tsx && echo "---" && wc -l src/pages/MvpPage.tsx

Repository: sopt-makers/hear-your-voice

Length of output: 122


🏁 Script executed:

# Read the specific lines from MvpPage.tsx
sed -n '71,110p' src/pages/MvpPage.tsx

Repository: sopt-makers/hear-your-voice

Length of output: 1595


🏁 Script executed:

# Check the entire MvpPage.tsx for keyboard handlers and ARIA attributes
cat -n src/pages/MvpPage.tsx | grep -E '(onKeyDown|onKeyUp|aria-|role=|SearchField|Select)'

Repository: sopt-makers/hear-your-voice

Length of output: 454


🏁 Script executed:

# Check if SearchField or Select from `@sopt-makers/ui` are imported anywhere in the project
rg "from '@sopt-makers/ui'" --type typescript

Repository: sopt-makers/hear-your-voice

Length of output: 105


🏁 Script executed:

# Fix the rg search to use proper file type flag
rg "from '@sopt-makers/ui'" -t ts -t tsx

Repository: sopt-makers/hear-your-voice

Length of output: 98


🏁 Script executed:

# Check the entire MvpPage.tsx for imports and any keyboard event handlers
head -40 src/pages/MvpPage.tsx

Repository: sopt-makers/hear-your-voice

Length of output: 1430


🏁 Script executed:

# Check if SearchField or Select components are used anywhere else in the project
rg "SearchField|Select" --type ts --type tsx | grep -E "(SearchField|Select)" | head -20

Repository: sopt-makers/hear-your-voice

Length of output: 98


🏁 Script executed:

# Search for SearchField or Select imports/usage without type flag
rg "SearchField|Select" | grep -v node_modules | head -20

Repository: sopt-makers/hear-your-voice

Length of output: 1693


🏁 Script executed:

# Check if there are other custom implementations of searchable dropdowns/combobox in components
fd -e ts -e tsx src/components | head -10

Repository: sopt-makers/hear-your-voice

Length of output: 432


🏁 Script executed:

# Verify the accessibility issue by checking for keyboard event handlers in MvpPage.tsx
rg "onKey" src/pages/MvpPage.tsx

Repository: sopt-makers/hear-your-voice

Length of output: 53


커스텀 콤보박스 접근성 부족.

검색 input + 드롭다운을 직접 구현하고 있는데, 키보드 내비게이션(↑/↓/Enter/Esc)과 role="combobox"/role="listbox"/aria-expanded/aria-activedescendant 등이 전혀 없어 키보드/스크린리더 사용자가 멤버를 선택할 수 없습니다.

@sopt-makers/ui 2.11.0이 이미 프로젝트 의존성에 포함되어 있고 SearchField, Select 컴포넌트를 제공하므로, 직접 구현 대신 기존 라이브러리 컴포넌트 재사용을 먼저 검토해 주세요. 라이브러리 컴포넌트는 접근성을 기본으로 구현하고 있어 시간을 절약할 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/MvpPage.tsx` around lines 71 - 110, The custom search + dropdown
lacks ARIA roles and keyboard support; replace it by using the existing
accessible components from `@sopt-makers/ui` (SearchField or Select) instead of
the manual input/list logic: wire the component's value to searchQuery, map
filteredMembers to the component's options, forward selection events to
handleSelectMember, and remove the custom dropdown rendering (the block using
filteredMembers.map and the input with clearButton) so the library component
manages role="combobox", aria-expanded, keyboard navigation, and
aria-activedescendant for you.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

SearchField, Select 컴포넌트에는 필터링 기능이 없어서 새로 구현했어.
접근성은 우선 핸드폰으로만 사용하기 때문에 문제가 되지 않는다고 판단돼.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@yungu0010 설명 감사해요! @sopt-makers/ui의 SearchField/Select에 필터링 기능이 없어서 직접 구현하셨군요. 그리고 현재 핸드폰 전용 서비스라면 키보드 내비게이션 접근성 이슈는 해당되지 않겠네요. 납득됩니다 👍

(°‿°🐰)


🧠 Learnings used
Learnt from: CR
Repo: sopt-makers/hear-your-voice PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-22T08:56:59.118Z
Learning: Applies to src/{components,pages,hooks}/**/*.{ts,tsx} : Manage survey form data through `CommentFormContext` (`src/context/CommentFormContext.tsx`)

Comment thread src/pages/MvpPage.tsx Outdated
yungu0010 and others added 3 commits April 22, 2026 20:51
- FieldSection 컴포넌트 신규 추가 (paddingTop:24, paddingBottom:12, gap:28)
- StepLayout contentSection 좌우 패딩 20px → 28px 통일
- MvpPage, UserInfoPage에 FieldSection 적용 (body/fields/inputWrapper 래퍼 제거)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@yungu0010 yungu0010 changed the title Refactor/#26 refactor/#26: 공통된 padding 설정 컴포넌트화 Apr 22, 2026
yungu0010 and others added 2 commits April 22, 2026 21:05
- rebase 충돌 해결 후 남아있던 중복 selectedMember 블록 제거
  (chipList ul + chipWrapper div 두 개가 동시에 렌더링되던 문제)
- searchContainer 하위 요소 4칸 들여쓰기 수정
- chipList → chipWrapper (div) 로 단일화, 올바른 HTML 구조 유지

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 페이지 플로우 step 총수 7→6으로 수정, MvpPage step 6→5 수정
- 레이아웃 기준선 섹션 추가: StepLayout 좌우 28px, FieldSection 설계 의도 명시
- AI Agent 작업 지침에 push 전 CLAUDE.md 업데이트 체크리스트 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@yungu0010 yungu0010 merged commit 51e9068 into develop Apr 22, 2026
1 check passed
@yungu0010 yungu0010 self-assigned this Apr 22, 2026
@yungu0010 yungu0010 deleted the refactor/#26 branch April 22, 2026 12:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor: 공통된 padding 영역 컴포넌트화

1 participant