Feature/#64 component feat#65
Conversation
📝 WalkthroughWalkthroughThis PR extends the icon and button component system with sizing variants, adds EMAIL input type support, refactors the navigation sidebar with smooth fold/unfold transitions, updates footer and header styling, and consolidates auth header logic into a shared utility. ChangesComponent UI System and Navigation Updates
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@jobdri/src/components/common/buttons/IconButton.tsx`:
- Around line 31-35: The small variant of IconButton produces
inconsistent/insufficient interior space because padding remains fixed (p-2.5)
while the container and icon classes shrink to h-6 w-6; update IconButton to
compute size-aware spacing: when props.size === "small" set a smaller padding
(e.g., p-1 or p-1.5) or alternatively enforce a minimum container dimension that
accommodates the small icon (adjust the size branch that currently outputs "h-6
w-6"), and ensure the icon element(s) use a matching small icon class rather
than a fixed large icon size; modify the conditional class list in the
IconButton component (the expression that uses size, className, active, and
buttonProps.disabled) so small uses consistent paired container (height/width)
and padding values to prevent layout collapse.
In `@jobdri/src/components/common/buttons/IconOnlyButton.tsx`:
- Line 27: The component IconOnlyButton currently computes closeIconType but
always passes closeIconType to the rendered icon (overriding the public prop
iconType); update the render to prefer the prop iconType when provided and fall
back to closeIconType otherwise (e.g., use iconType if truthy, else
closeIconType) so callers' iconType values are respected; look for the computed
constant closeIconType and the prop iconType in the IconOnlyButton component and
change the value used in the JSX where the icon is rendered.
In `@jobdri/src/components/common/lnb/Lnb.tsx`:
- Around line 158-174: The credit button remains focusable when the LNB is
folded; update the folded branch to make hidden controls non-interactive by
adding aria-hidden={isFold} to the toggle container and make the button
unfocusable when folded (e.g., set tabIndex={isFold ? -1 : 0} and
aria-hidden={isFold} on the <button> in the block that contains isFold), or
alternatively render null when folded; target the JSX around isFold and the
button onClick (the button that navigates to "/credit") to apply these
attributes so keyboard users cannot tab to the hidden control.
- Around line 145-147: The current fold/unfold uses w-auto/h-auto which can't be
animated reliably; update the Lnb component to transition numeric constraints
instead: replace uses of "w-auto" with a numeric max-width (e.g., switch the
class logic that currently toggles between "w-0 opacity-0" and "w-auto
opacity-100" to toggle between "max-w-0 opacity-0" and "max-w-[<px>]
opacity-100") and similarly replace "h-auto" toggles with "max-h-0" vs
"max-h-[<px>]" (or a sufficiently large fixed pixel value) and keep
overflow-hidden and transition-[opacity,max-width] /
transition-[opacity,max-height]; apply the same change for every occurrence of
the transition-[opacity,width] and transition-[opacity,height] class strings in
Lnb.tsx and use the isFold boolean to control max-w/max-h instead of auto so the
animation is smooth and not jumpy.
🪄 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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: beb500e5-ca93-45c1-b9e0-3e58db0ee881
⛔ Files ignored due to path filters (4)
jobdri/src/assets/ic_Close_S.svgis excluded by!**/*.svgjobdri/src/assets/ic_Email.svgis excluded by!**/*.svgjobdri/src/assets/ic_LOGO_minimum.svgis excluded by!**/*.svgjobdri/src/assets/ic_LOGO_minimum_favi.svgis excluded by!**/*.svg
📒 Files selected for processing (13)
jobdri/src/app/page.tsxjobdri/src/components/common/buttons/IconButton.tsxjobdri/src/components/common/buttons/IconOnlyButton.tsxjobdri/src/components/common/footer/BusinessFooter.tsxjobdri/src/components/common/footer/Footer.tsxjobdri/src/components/common/header/Header.tsxjobdri/src/components/common/icons/Icon.tsxjobdri/src/components/common/icons/IconBox.tsxjobdri/src/components/common/input/InputMain.tsxjobdri/src/components/common/lnb/Lnb.tsxjobdri/src/components/common/toast/Toast.tsxjobdri/src/components/login/EmailLoginScreen.tsxjobdri/src/lib/api/questions.ts
💤 Files with no reviewable changes (1)
- jobdri/src/lib/api/questions.ts
| "flex items-center justify-center gap-2.5 rounded-icon-round bg-bg-white p-2.5", | ||
| buttonProps.disabled ? "cursor-not-allowed" : "cursor-pointer", | ||
| active ? "text-icon-neutral-heavy" : "text-icon-neutral-assistive", | ||
| className, | ||
| size === "small" ? "h-6 w-6" : "h-10 w-10", |
There was a problem hiding this comment.
Small variant sizing is internally inconsistent.
Line 31 keeps fixed p-2.5 and Line 41 keeps a fixed h-6 w-6 icon, while Line 35 can shrink the button to h-6 w-6. The small button ends up with no real content room, so icon rendering/layout is unstable.
Proposed fix
className={clsx(
- "flex items-center justify-center gap-2.5 rounded-icon-round bg-bg-white p-2.5",
+ "flex items-center justify-center gap-2.5 rounded-icon-round bg-bg-white",
buttonProps.disabled ? "cursor-not-allowed" : "cursor-pointer",
active ? "text-icon-neutral-heavy" : "text-icon-neutral-assistive",
className,
- size === "small" ? "h-6 w-6" : "h-10 w-10",
+ size === "small" ? "h-6 w-6 p-1" : "h-10 w-10 p-2",
)}
{...buttonProps}
>
<Icon
type={directionIconType[direction]}
- className="aspect-square h-6 w-6 shrink-0"
+ className={clsx(
+ "aspect-square shrink-0",
+ size === "small" ? "h-4 w-4" : "h-6 w-6",
+ )}
/>Also applies to: 39-41
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@jobdri/src/components/common/buttons/IconButton.tsx` around lines 31 - 35,
The small variant of IconButton produces inconsistent/insufficient interior
space because padding remains fixed (p-2.5) while the container and icon classes
shrink to h-6 w-6; update IconButton to compute size-aware spacing: when
props.size === "small" set a smaller padding (e.g., p-1 or p-1.5) or
alternatively enforce a minimum container dimension that accommodates the small
icon (adjust the size branch that currently outputs "h-6 w-6"), and ensure the
icon element(s) use a matching small icon class rather than a fixed large icon
size; modify the conditional class list in the IconButton component (the
expression that uses size, className, active, and buttonProps.disabled) so small
uses consistent paired container (height/width) and padding values to prevent
layout collapse.
| size = "default", | ||
| ...buttonProps | ||
| }: IconOnlyButtonProps) { | ||
| const closeIconType = size === "small" ? "CLOSE_S" : "CLOSE_M"; |
There was a problem hiding this comment.
iconType is ignored after this change.
Line 42 always renders closeIconType, so callers passing iconType get overridden. This is a behavior regression for a public prop.
Proposed fix
- const closeIconType = size === "small" ? "CLOSE_S" : "CLOSE_M";
+ const resolvedIconType =
+ size === "small" && iconType === "CLOSE_M" ? "CLOSE_S" : iconType;
@@
- <Icon
- type={closeIconType}
- className={
- (clsx("shrink-0 "), size === "small" ? "h-5 w-5" : "h-6 w-6")
- }
- />
+ <Icon
+ type={resolvedIconType}
+ className={clsx("shrink-0", size === "small" ? "h-5 w-5" : "h-6 w-6")}
+ />Also applies to: 41-45
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@jobdri/src/components/common/buttons/IconOnlyButton.tsx` at line 27, The
component IconOnlyButton currently computes closeIconType but always passes
closeIconType to the rendered icon (overriding the public prop iconType); update
the render to prefer the prop iconType when provided and fall back to
closeIconType otherwise (e.g., use iconType if truthy, else closeIconType) so
callers' iconType values are respected; look for the computed constant
closeIconType and the prop iconType in the IconOnlyButton component and change
the value used in the JSX where the icon is rendered.
| className={`overflow-hidden whitespace-nowrap transition-[opacity,width] duration-150 ${ | ||
| isFold ? "w-0 opacity-0" : "w-auto opacity-100" | ||
| }`} |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Can CSS transitions animate width/height when one state is auto? What are recommended alternatives (max-width/max-height, transform, grid) for smooth collapse animations?
💡 Result:
Yes—within current CSS specifications and browser implementations, transitions/animations generally should not rely on a state change where one endpoint is auto (e.g., height: 0 → height: auto). MDN notes that the specification recommends not animating from and to auto, and that behavior can be unpredictable across engines [1]. Chrome’s docs similarly frame the problem as “animate to intrinsic sizing keywords like auto” being non-trivial, and introduce newer opt-in mechanisms [2]. Recommended alternatives for smooth collapse/expand animations 1) Use max-height / max-width (classic workaround) Animate a numeric ceiling instead of auto: e.g., max-height: 0 → max-height: <big enough>, with overflow: hidden. This is the commonly cited “cannot animate height to auto directly” workaround [3][4]. 2) Use CSS Grid row animation (0fr → 1fr) A grid-based approach animates grid-template-rows between 0fr (collapsed) and 1fr (expanded), so the grid row can take the content’s intrinsic size without needing auto in the transition itself [5][6]. A widely referenced implementation is:.expander { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.5s ease; }.expander.expanded { grid-template-rows: 1fr; } (and pair with overflow: hidden on the inner content if needed) [6]. 3) Prefer transform/opacity when possible For many UI elements, switching to transform (and opacity) avoids layout-driven properties. General guidance is to animate transform/opacity rather than width/height for performance/smoothness, because width/height are layout-affecting [7]. 4) If you specifically need height/width + “intrinsic” end state: opt into intrinsic-size interpolation (newer CSS) Chrome documents a newer mechanism that enables transitions/animations to intrinsic sizing keywords by using interpolate-size (opt-in) [2]. Example::root { interpolate-size: allow-keywords; } Then an element can transition to height: auto (in browsers with support) [2]. Additionally, the same theme shows up via calc-size() (math around intrinsic sizing keywords) as another route to animating to/from auto in browsers that implement it [8][9]. 5) For “first paint” / display toggles: use transition start controls When collapsing/expanding with display: none/showing, you typically need @starting-style and transition-behavior: allow-discrete to ensure transitions start on the first style update. MDN’s transition guide shows @starting-style and allow-discrete usage when transitioning display and establishing a before-start style [1]. Practical rule of thumb - If you need a CSS-only solution today: use max-height/max-width or the grid-template-rows technique [3][6]. - If you can use non-size animations: use transform/opacity [7]. - If you truly need auto-exact sizing and can target modern Chromium (or browsers with support): consider interpolate-size: allow-keywords (and/or calc-size()) [2][8]. If you tell me your target browsers (Chrome/Firefox/Safari versions) and whether you’re animating a dropdown, accordion, or side panel, I can recommend the best concrete pattern and code.
Citations:
- 1: https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Transitions/Using
- 2: https://developer.chrome.google.cn/docs/css-ui/animate-to-height-auto
- 3: https://stackoverflow.com/questions/3508605/how-can-i-transition-height-0-to-height-auto-using-css
- 4: https://bugzilla.mozilla.org/show_bug.cgi?id=571344
- 5: https://thelinuxcode.com/how-to-transition-height-from-0-to-auto-using-css-real-world-patterns/
- 6: https://keithjgrant.com/posts/2023/04/transitioning-to-height-auto/
- 7: https://dev.to/edriso/learning-css-as-if-you-built-it-yourself-3ppg
- 8: https://css-weekly.com/transition-to-height-auto-display-none-using-pure-css
- 9: https://css-tricks.com/transitioning-to-auto-height/
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Show relevant sections around the referenced lines
sed -n '120,220p' jobdri/src/components/common/lnb/Lnb.tsx | nl -ba
# Search for other fold/unfold className patterns in this file
rg -n "transition-\\[opacity,(width|height)\\]|w-auto|h-auto|max-w-|max-h-|transition-\\[opacity,max-(width|height)\\]|interpolate-size|calc-size\\(" jobdri/src/components/common/lnb/Lnb.tsx
# Search repo for interpolate-size usage
rg -n "interpolate-size|calc-size\\(" -S .Repository: JobDri-Developer/FrontEnd
Length of output: 112
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '120,220p' jobdri/src/components/common/lnb/Lnb.tsx | nl -ba
rg -n "transition-\\[opacity,(width|height)\\]|w-auto|h-auto|max-w-|max-h-|transition-\\[opacity,max-(width|height)\\]|interpolate-size|calc-size\\(" jobdri/src/components/common/lnb/Lnb.tsx
rg -n "interpolate-size|calc-size\\(" -S .Repository: JobDri-Developer/FrontEnd
Length of output: 112
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Show relevant sections around the referenced lines
sed -n '120,220p' jobdri/src/components/common/lnb/Lnb.tsx | nl -ba
# Search for other fold/unfold className patterns in this file
rg -n "transition-\\[opacity,(width|height)\\]|w-auto|h-auto|max-w-|max-h-|transition-\\[opacity,max-(width|height)\\]|interpolate-size|calc-size\\(" jobdri/src/components/common/lnb/Lnb.tsx
# Search repo for interpolate-size usage
rg -n "interpolate-size|calc-size\\(" -S .Repository: JobDri-Developer/FrontEnd
Length of output: 112
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="jobdri/src/components/common/lnb/Lnb.tsx"
echo "=== Lnb.tsx excerpt (lines 120-220) ==="
# Use cat -n to provide line numbers (since nl isn't available)
sed -n '120,220p' "$FILE" | cat -n
echo
echo "=== rg hits in Lnb.tsx ==="
rg -n "w-auto|h-auto|transition-\\[opacity,(width|height)\\]|transition-\\[opacity,max-(width|height)\\]|max-w-|max-h-|transition-\\[opacity,width\\]|transition-\\[opacity,height\\]" "$FILE" || true
echo
echo "=== rg hits for interpolate-size/calc-size across repo ==="
rg -n "interpolate-size|calc-size\\(" -S . || trueRepository: JobDri-Developer/FrontEnd
Length of output: 5457
Avoid auto endpoints in fold/unfold width/height transitions to prevent abrupt animation
Lnb.tsxtransitionsw-auto/h-autointransition-[opacity,width]andtransition-[opacity,height](lines 145-147, 159-161, and 195-197). Transitions to/fromautoaren’t reliably animatable, so the fold/unfold will jump.- Replace
w-auto/h-autowith animatable numeric constraints (e.g.,max-width/max-heightwithoverflow-hiddenusing sufficiently large bounds), or use a grid-row (grid-template-rows) / transform-based approach.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@jobdri/src/components/common/lnb/Lnb.tsx` around lines 145 - 147, The current
fold/unfold uses w-auto/h-auto which can't be animated reliably; update the Lnb
component to transition numeric constraints instead: replace uses of "w-auto"
with a numeric max-width (e.g., switch the class logic that currently toggles
between "w-0 opacity-0" and "w-auto opacity-100" to toggle between "max-w-0
opacity-0" and "max-w-[<px>] opacity-100") and similarly replace "h-auto"
toggles with "max-h-0" vs "max-h-[<px>]" (or a sufficiently large fixed pixel
value) and keep overflow-hidden and transition-[opacity,max-width] /
transition-[opacity,max-height]; apply the same change for every occurrence of
the transition-[opacity,width] and transition-[opacity,height] class strings in
Lnb.tsx and use the isFold boolean to control max-w/max-h instead of auto so the
animation is smooth and not jumpy.
| <div | ||
| className={`overflow-hidden transition-[opacity,height] duration-150 w-full ${ | ||
| isFold ? "h-0 opacity-0" : "h-auto opacity-100" | ||
| }`} | ||
| > | ||
| <div className="flex w-full items-center justify-between px-2 py-2"> | ||
| <button | ||
| type="button" | ||
| onClick={() => router.push("/credit")} | ||
| className="flex items-center gap-[3px] text-label14-med text-icon-neutral-default [font-feature-settings:'liga'_off,'clig'_off] hover:text-text-neutral-title" | ||
| > | ||
| <span>크레딧</span> | ||
| <Icon | ||
| type="EX_LINK" | ||
| className="h-4 w-4 text-icon-neutral-assistive" | ||
| /> | ||
| </button> |
There was a problem hiding this comment.
Hidden credit action remains focusable when folded.
On folded state, the credit section is visually hidden but still mounted and interactive. Keyboard users can tab to an invisible button (Line 164), which is an accessibility bug.
Suggested fix
- <div
- className={`overflow-hidden transition-[opacity,height] duration-150 w-full ${
- isFold ? "h-0 opacity-0" : "h-auto opacity-100"
- }`}
- >
+ <div
+ aria-hidden={isFold}
+ className={`overflow-hidden transition-[opacity,max-height] duration-150 w-full ${
+ isFold ? "max-h-0 opacity-0 pointer-events-none" : "max-h-24 opacity-100"
+ }`}
+ >
<div className="flex w-full items-center justify-between px-2 py-2">
<button
type="button"
+ tabIndex={isFold ? -1 : 0}
onClick={() => router.push("/credit")}
className="flex items-center gap-[3px] text-label14-med text-icon-neutral-default [font-feature-settings:'liga'_off,'clig'_off] hover:text-text-neutral-title"
>📝 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={`overflow-hidden transition-[opacity,height] duration-150 w-full ${ | |
| isFold ? "h-0 opacity-0" : "h-auto opacity-100" | |
| }`} | |
| > | |
| <div className="flex w-full items-center justify-between px-2 py-2"> | |
| <button | |
| type="button" | |
| onClick={() => router.push("/credit")} | |
| className="flex items-center gap-[3px] text-label14-med text-icon-neutral-default [font-feature-settings:'liga'_off,'clig'_off] hover:text-text-neutral-title" | |
| > | |
| <span>크레딧</span> | |
| <Icon | |
| type="EX_LINK" | |
| className="h-4 w-4 text-icon-neutral-assistive" | |
| /> | |
| </button> | |
| <div | |
| aria-hidden={isFold} | |
| className={`overflow-hidden transition-[opacity,max-height] duration-150 w-full ${ | |
| isFold ? "max-h-0 opacity-0 pointer-events-none" : "max-h-24 opacity-100" | |
| }`} | |
| > | |
| <div className="flex w-full items-center justify-between px-2 py-2"> | |
| <button | |
| type="button" | |
| tabIndex={isFold ? -1 : 0} | |
| onClick={() => router.push("/credit")} | |
| className="flex items-center gap-[3px] text-label14-med text-icon-neutral-default [font-feature-settings:'liga'_off,'clig'_off] hover:text-text-neutral-title" | |
| > | |
| <span>크레딧</span> | |
| <Icon | |
| type="EX_LINK" | |
| className="h-4 w-4 text-icon-neutral-assistive" | |
| /> | |
| </button> |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@jobdri/src/components/common/lnb/Lnb.tsx` around lines 158 - 174, The credit
button remains focusable when the LNB is folded; update the folded branch to
make hidden controls non-interactive by adding aria-hidden={isFold} to the
toggle container and make the button unfocusable when folded (e.g., set
tabIndex={isFold ? -1 : 0} and aria-hidden={isFold} on the <button> in the block
that contains isFold), or alternatively render null when folded; target the JSX
around isFold and the button onClick (the button that navigates to "/credit") to
apply these attributes so keyboard users cannot tab to the hidden control.
🔗 관련 이슈
#64
📋 작업 개요
공통 컴포넌트 UI 개선 작업입니다.
✨ 주요 변경사항
결과 페이지 신규 구현
ApplyResult— Trybar + Sidebar + 콘텐츠 영역 전체 레이아웃Trybar— 시도 회차 표시 (sequence API 연동)Sidebar/SidebarItem— 개요 / 개선안 상세 아코디언, 문항별 sub 아이템OverviewSection— 총점 원형 그래프 + 피드백 + 3개 요약 카드ScoreCircle— SVG stroke-dashoffset 기반 원형 점수 그래프Alret— 60점 기준 경고/완료 메시지 분기SummaryCard— 직무적합도 / 성과구체성 / 완성도 카드 (60점 이하 빨간색)개선안 상세 뷰 (DetailSection)
DetailAnnotationPanel— ChipTag + reason + sentence + 개선 예시highlightStyles.ts—proven/mentioned/fabricateddefault · selected 스타일 분리색상 토큰 추가 (
color.css)green-150#F3F9E5green-700#50B100pink-100#FFEFFBpink-200#FFE1F8pink-400#FF29D1ChipTag 상태 추가
proven(적절함) /mentioned(신뢰성 부족) /fabricated(구체성 부족)LNB 개선
transition-[width] duration-300)w-0 opacity-0처리로 자연스러운 페이드/credit라우팅 연결기타 공통 컴포넌트
Header좌측 버튼 라벨 "돌아가기" → "메인으로"InputMainiconMap키 오류 수정 ("PROFILE"→"ID") 및 점 표기법 오류 수정API 연동 수정
saveApply요청 바디 오류 수정fetchSelectedQuestionsindex 기반 ID →analysis.questions인덱스 조회 통일h-screen→h-full(헤더 영역 제외)💡 코드 설명 및 참고사항
📸 스크린샷 (UI 변경 시)
🔍 리뷰 요구사항 (Reviewers)
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Style