[JDDESIGN-3] Feat: 모의지원 기본화면 HIFI UI 구현 및 API 연동 #72
Conversation
📝 WalkthroughWalkthroughThis PR introduces a text-paste input method for job postings, comprehensively refactors the mock application home UI with reusable component library and utilities, integrates Lottie animations for loading states, updates mock apply identity resolution throughout the resume flow, and refines grid layout and styling across the application. ChangesText Input Method & Mock Application Home Refactor
🎯 4 (Complex) | ⏱️ ~60 minutes Possibly Related PRs
Suggested Reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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: 7
🧹 Nitpick comments (1)
jobdri/src/components/mock-application/QuestionGenerationLoading.tsx (1)
45-52: ⚡ Quick winRespect reduced-motion preference for looping Lottie animations.
Line 48/50 currently always animates. Please gate autoplay/loop with
prefers-reduced-motionso motion-sensitive users get a static fallback.♿ Proposed change
@@ function LoadingGraphic({ animationData, className, + shouldAnimate, }: { animationData: unknown; className: string; + shouldAnimate: boolean; }) { return ( <LottiePlayer aria-hidden animationData={animationData} - autoplay + autoplay={shouldAnimate} className={className} - loop + loop={shouldAnimate} rendererSettings={{ preserveAspectRatio: "xMidYMid meet" }} /> ); } @@ export default function QuestionGenerationLoading({ companyName, jobName, durationMs, }: QuestionGenerationLoadingProps) { const [activeStep, setActiveStep] = useState(0); + const [prefersReducedMotion, setPrefersReducedMotion] = useState(false); + + useEffect(() => { + const media = window.matchMedia("(prefers-reduced-motion: reduce)"); + const onChange = () => setPrefersReducedMotion(media.matches); + onChange(); + media.addEventListener("change", onChange); + return () => media.removeEventListener("change", onChange); + }, []); @@ <LoadingGraphic animationData={questionLoadingSparkle} className="h-5 w-5" + shouldAnimate={!prefersReducedMotion} /> @@ <LoadingGraphic animationData={questionLoadingBook} className="h-[223.27px] w-[280px] shrink-0" + shouldAnimate={!prefersReducedMotion} />Also applies to: 74-77, 153-156
🤖 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/mock-application/QuestionGenerationLoading.tsx` around lines 45 - 52, The LottiePlayer instances are always autoplaying/looping which ignores users' prefers-reduced-motion setting; update each LottiePlayer (the instances rendered in QuestionGenerationLoading) to detect prefers-reduced-motion (e.g., via window.matchMedia('(prefers-reduced-motion: reduce)') or a usePrefersReducedMotion hook) and only set autoplay and loop when the preference is not reduced, otherwise render a static fallback (no autoplay/loop) or disable animation; change the autoplay and loop props on the LottiePlayer components accordingly (affecting the occurrences around the existing LottiePlayer props).
🤖 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/app/apply/virtual/`[id]/questions/QuestionsPageClient.tsx:
- Around line 25-36: The lookup for jobPostingId using
getMockApplyResumeRecords() is not guarded causing router.push to proceed
without a stable id; update the flow in QuestionsPageClient.tsx to check the
resolved jobPostingId after calling getMockApplyResumeRecords() (using the
mockApplyId), and if it is undefined fail fast or recover (e.g., surface an
error/toast, call an API to fetch/fallback, or abort) instead of executing
saveQuestions/updateMockApplyResumeStatus and calling router.push; only call
saveQuestions, updateMockApplyResumeStatus, and router.push when jobPostingId is
present (or when a confirmed fallback has been obtained).
In `@jobdri/src/app/apply/virtual/`[id]/write/WritePageClient.tsx:
- Around line 38-43: The code currently falls back to 0 for jobPostingId
(variable jobPostingId computed from jobPostingIdParam or
getMockApplyResumeRecords()), which can cause routing to
/apply/virtual/0/result; remove the `|| 0` fallback so jobPostingId is undefined
when missing and update the submit success flow that does the redirect to
`/apply/virtual/${jobPostingId}/result` to first validate jobPostingId (e.g., if
(!jobPostingId) handle error/log and abort navigation or surface a proper error)
so you never navigate to id 0; ensure both the jobPostingId computation and the
redirect logic that references jobPostingId are changed accordingly.
In `@jobdri/src/components/mock-application/home/applicationHomeUtils.ts`:
- Around line 153-156: The createRows function must guard against non-positive
or non-integer sizes to avoid invalid array lengths; update createRows to
validate the size parameter (e.g., if size is not a positive integer or size <=
0) and immediately throw a clear RangeError or TypeError (with a short message)
before computing Math.ceil/Array.from so callers get a fast, explicit failure;
ensure the check is placed at the top of createRows and references the existing
createRows function signature.
- Around line 55-60: The matching in findLocalResumeStatus currently treats
mockApplyId and jobPostingId as equivalent; change it to first attempt to find a
record where record.mockApplyId === item.mockApplyId and only if that returns
undefined, fall back to finding by record.jobPostingId === item.jobPostingId
(using getMockApplyResumeRecords and the same MockApplyHomeItem fields). Ensure
the comparison uses strict equality and return the record found by mockApplyId
when present so status routing and step navigation use mockApplyId as the
primary identity.
In `@jobdri/src/components/mock-application/home/ApplicationKebabButton.tsx`:
- Around line 28-38: The retry menu item is being shown when showRetry is true
even if no handler is provided; update the conditional that builds the actions
array in ApplicationKebabButton (the block that currently checks showRetry) to
only include the "재도전하기" entry when showRetry is true AND onRetryClick is a
function (or non-null), so the menu item is omitted if onRetryClick is missing;
preserve the existing behavior of closing via setOpen(false) and calling
onRetryClick() when present.
In `@jobdri/src/components/mock-application/MockApplicationHomePageClient.tsx`:
- Around line 217-229: The code currently calls
removeApplicationLocally(targetApplication) before awaiting deleteJobPosting,
which causes the UI/cache to drop the record even if the API delete fails;
change the flow so that deleteJobPosting(targetApplication.jobPostingId) is
awaited inside the try block first, then on success call
removeApplicationLocally(...) and setShowDeleteToast(true); on failure (catch)
do not remove from local state — instead setApplicationsErrorMessage(...) and
leave state intact (or re-add the application if you must keep the optimistic
removal), and still call setShowDeleteConfirm(false) and
setDeleteTargetApplication(null) as appropriate; update references to
setShowDeleteConfirm, setDeleteTargetApplication, removeApplicationLocally,
deleteJobPosting, setShowDeleteToast, and setApplicationsErrorMessage
accordingly.
In `@jobdri/src/styles/grid.css`:
- Around line 45-49: The .container-lnb rule forces a hard minimum by using
min-width: var(--width-lnb-min) alongside width: clamp(...), causing horizontal
overflow on narrow viewports; remove the min-width declaration (or override it
to min-width: 0 in the responsive container query) so the clamp can actually
shrink below --width-lnb-min. Update the CSS rule for .container-lnb (or the
`@container` content-frame-lnb override) to eliminate the min-width restriction so
the element can fit narrow screens.
---
Nitpick comments:
In `@jobdri/src/components/mock-application/QuestionGenerationLoading.tsx`:
- Around line 45-52: The LottiePlayer instances are always autoplaying/looping
which ignores users' prefers-reduced-motion setting; update each LottiePlayer
(the instances rendered in QuestionGenerationLoading) to detect
prefers-reduced-motion (e.g., via window.matchMedia('(prefers-reduced-motion:
reduce)') or a usePrefersReducedMotion hook) and only set autoplay and loop when
the preference is not reduced, otherwise render a static fallback (no
autoplay/loop) or disable animation; change the autoplay and loop props on the
LottiePlayer components accordingly (affecting the occurrences around the
existing LottiePlayer props).
🪄 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: c238a451-cb3b-4aa0-b7af-f459116e60e8
⛔ Files ignored due to path filters (6)
jobdri/pnpm-lock.yamlis excluded by!**/pnpm-lock.yamljobdri/src/assets/ic_Text.svgis excluded by!**/*.svgjobdri/src/assets/ic_text.svgis excluded by!**/*.svgjobdri/src/assets/img_basic_Step1.svgis excluded by!**/*.svgjobdri/src/assets/img_basic_Step2.svgis excluded by!**/*.svgjobdri/src/assets/img_basic_Step3.svgis excluded by!**/*.svg
📒 Files selected for processing (30)
jobdri/components/common/LoadMotion.tsxjobdri/package.jsonjobdri/src/app/apply/virtual/[id]/(jd)/jd-input/JdInputPageClient.tsxjobdri/src/app/apply/virtual/[id]/(jd)/jd-input/page.tsxjobdri/src/app/apply/virtual/[id]/questions/QuestionsPageClient.tsxjobdri/src/app/apply/virtual/[id]/write/WritePageClient.tsxjobdri/src/assets/lottie/question-loading-book.jsonjobdri/src/assets/lottie/question-loading-sparkle.jsonjobdri/src/components/common/buttons/ButtonCtaModal.tsxjobdri/src/components/common/buttons/TextButton.tsxjobdri/src/components/common/cards/Method1Card.tsxjobdri/src/components/common/icons/Icon.tsxjobdri/src/components/common/lnb/Lnb.tsxjobdri/src/components/mock-application/MockApplicationHomePageClient.tsxjobdri/src/components/mock-application/QuestionGenerationLoading.tsxjobdri/src/components/mock-application/home/ApplicationCardShared.tsxjobdri/src/components/mock-application/home/ApplicationKebabButton.tsxjobdri/src/components/mock-application/home/ApplicationProgressSteps.tsxjobdri/src/components/mock-application/home/EmptyApplicationState.tsxjobdri/src/components/mock-application/home/MockApplicationHomeIntro.tsxjobdri/src/components/mock-application/home/PausedApplicationCard.tsxjobdri/src/components/mock-application/home/ResultApplicationCard.tsxjobdri/src/components/mock-application/home/SavedApplicationsModal.tsxjobdri/src/components/mock-application/home/applicationHomeUtils.tsjobdri/src/components/mock-application/home/homeSteps.tsjobdri/src/components/mock-application/home/index.tsjobdri/src/components/mock-application/home/types.tsjobdri/src/lib/api/jobPostings.tsjobdri/src/styles/grid.cssjobdri/src/styles/shadow.css
| const mockApplyId = Number(id); | ||
| const jobPostingId = getMockApplyResumeRecords().find( | ||
| (record) => record.mockApplyId === mockApplyId, | ||
| )?.jobPostingId; | ||
|
|
||
| await saveQuestions(Number(id), selectedQuestions); | ||
| updateMockApplyResumeStatus(Number(id), "ANSWER_WRITE"); | ||
| router.push(`/apply/virtual/${id}/write`); | ||
| updateMockApplyResumeStatus(mockApplyId, "ANSWER_WRITE"); | ||
| router.push( | ||
| `/apply/virtual/${id}/write${ | ||
| jobPostingId ? `?jobPostingId=${jobPostingId}` : "" | ||
| }`, | ||
| ); |
There was a problem hiding this comment.
Guard unresolved jobPostingId before navigation.
At Line 26-35, when the lookup misses, you still continue and push /write without jobPostingId. This leaves the next step without a stable identifier and can still lead to broken result routing later. Fail fast here (or recover via API) instead of silently continuing.
Suggested fix
const handleConfirm = async () => {
const mockApplyId = Number(id);
- const jobPostingId = getMockApplyResumeRecords().find(
+ const jobPostingId = getMockApplyResumeRecords().find(
(record) => record.mockApplyId === mockApplyId,
)?.jobPostingId;
+ if (!jobPostingId) {
+ // TODO: show recoverable error modal (or refetch by mockApplyId) before routing
+ return;
+ }
+
await saveQuestions(Number(id), selectedQuestions);
updateMockApplyResumeStatus(mockApplyId, "ANSWER_WRITE");
- router.push(
- `/apply/virtual/${id}/write${
- jobPostingId ? `?jobPostingId=${jobPostingId}` : ""
- }`,
- );
+ router.push(`/apply/virtual/${id}/write?jobPostingId=${jobPostingId}`);
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const mockApplyId = Number(id); | |
| const jobPostingId = getMockApplyResumeRecords().find( | |
| (record) => record.mockApplyId === mockApplyId, | |
| )?.jobPostingId; | |
| await saveQuestions(Number(id), selectedQuestions); | |
| updateMockApplyResumeStatus(Number(id), "ANSWER_WRITE"); | |
| router.push(`/apply/virtual/${id}/write`); | |
| updateMockApplyResumeStatus(mockApplyId, "ANSWER_WRITE"); | |
| router.push( | |
| `/apply/virtual/${id}/write${ | |
| jobPostingId ? `?jobPostingId=${jobPostingId}` : "" | |
| }`, | |
| ); | |
| const mockApplyId = Number(id); | |
| const jobPostingId = getMockApplyResumeRecords().find( | |
| (record) => record.mockApplyId === mockApplyId, | |
| )?.jobPostingId; | |
| if (!jobPostingId) { | |
| // TODO: show recoverable error modal (or refetch by mockApplyId) before routing | |
| return; | |
| } | |
| await saveQuestions(Number(id), selectedQuestions); | |
| updateMockApplyResumeStatus(mockApplyId, "ANSWER_WRITE"); | |
| router.push(`/apply/virtual/${id}/write?jobPostingId=${jobPostingId}`); |
🤖 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/app/apply/virtual/`[id]/questions/QuestionsPageClient.tsx around
lines 25 - 36, The lookup for jobPostingId using getMockApplyResumeRecords() is
not guarded causing router.push to proceed without a stable id; update the flow
in QuestionsPageClient.tsx to check the resolved jobPostingId after calling
getMockApplyResumeRecords() (using the mockApplyId), and if it is undefined fail
fast or recover (e.g., surface an error/toast, call an API to fetch/fallback, or
abort) instead of executing saveQuestions/updateMockApplyResumeStatus and
calling router.push; only call saveQuestions, updateMockApplyResumeStatus, and
router.push when jobPostingId is present (or when a confirmed fallback has been
obtained).
| const jobPostingId = | ||
| jobPostingIdParam || | ||
| getMockApplyResumeRecords().find( | ||
| (record) => record.mockApplyId === mockApplyId, | ||
| )?.jobPostingId || | ||
| 0; |
There was a problem hiding this comment.
Do not default jobPostingId to 0 in result routing flow.
At Line 38-43, the || 0 fallback can send users to /apply/virtual/0/result at Line 85 after a successful submit. That’s a high-impact failure path.
Suggested fix
- const jobPostingId =
+ const jobPostingId =
jobPostingIdParam ||
getMockApplyResumeRecords().find(
(record) => record.mockApplyId === mockApplyId,
- )?.jobPostingId ||
- 0;
+ )?.jobPostingId;
...
- router.push(
- `/apply/virtual/${jobPostingId}/result?sequence=${savedSequence}`,
- );
+ if (!jobPostingId) {
+ setShowAnalysisErrorModal(true);
+ shouldKeepLoading = false;
+ return;
+ }
+ router.push(`/apply/virtual/${jobPostingId}/result?sequence=${savedSequence}`);Also applies to: 84-86
🤖 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/app/apply/virtual/`[id]/write/WritePageClient.tsx around lines 38
- 43, The code currently falls back to 0 for jobPostingId (variable jobPostingId
computed from jobPostingIdParam or getMockApplyResumeRecords()), which can cause
routing to /apply/virtual/0/result; remove the `|| 0` fallback so jobPostingId
is undefined when missing and update the submit success flow that does the
redirect to `/apply/virtual/${jobPostingId}/result` to first validate
jobPostingId (e.g., if (!jobPostingId) handle error/log and abort navigation or
surface a proper error) so you never navigate to id 0; ensure both the
jobPostingId computation and the redirect logic that references jobPostingId are
changed accordingly.
| function findLocalResumeStatus(item: MockApplyHomeItem) { | ||
| const localRecord = getMockApplyResumeRecords().find( | ||
| (record) => | ||
| record.mockApplyId === item.mockApplyId || | ||
| record.jobPostingId === item.jobPostingId, | ||
| ); |
There was a problem hiding this comment.
Use mockApplyId as the primary identity when resolving local status.
Current matching can pick another record with the same jobPostingId, which can misclassify card status and route users to the wrong step.
🔧 Proposed fix
function findLocalResumeStatus(item: MockApplyHomeItem) {
- const localRecord = getMockApplyResumeRecords().find(
- (record) =>
- record.mockApplyId === item.mockApplyId ||
- record.jobPostingId === item.jobPostingId,
- );
+ const records = getMockApplyResumeRecords();
+ const localRecord =
+ records.find((record) => record.mockApplyId === item.mockApplyId) ??
+ records.find(
+ (record) =>
+ record.mockApplyId == null &&
+ record.jobPostingId === item.jobPostingId,
+ );
return localRecord?.status;
}🤖 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/mock-application/home/applicationHomeUtils.ts` around
lines 55 - 60, The matching in findLocalResumeStatus currently treats
mockApplyId and jobPostingId as equivalent; change it to first attempt to find a
record where record.mockApplyId === item.mockApplyId and only if that returns
undefined, fall back to finding by record.jobPostingId === item.jobPostingId
(using getMockApplyResumeRecords and the same MockApplyHomeItem fields). Ensure
the comparison uses strict equality and return the record found by mockApplyId
when present so status routing and step navigation use mockApplyId as the
primary identity.
| export function createRows<T>(items: T[], size: number) { | ||
| return Array.from({ length: Math.ceil(items.length / size) }, (_, index) => | ||
| items.slice(index * size, index * size + size), | ||
| ); |
There was a problem hiding this comment.
Guard createRows against non-positive size.
size of 0 or negative values can crash with invalid array length. Add a fast validation.
🛡️ Proposed fix
export function createRows<T>(items: T[], size: number) {
+ if (size <= 0) {
+ return [];
+ }
return Array.from({ length: Math.ceil(items.length / size) }, (_, index) =>
items.slice(index * size, index * size + size),
);
}🤖 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/mock-application/home/applicationHomeUtils.ts` around
lines 153 - 156, The createRows function must guard against non-positive or
non-integer sizes to avoid invalid array lengths; update createRows to validate
the size parameter (e.g., if size is not a positive integer or size <= 0) and
immediately throw a clear RangeError or TypeError (with a short message) before
computing Math.ceil/Array.from so callers get a fast, explicit failure; ensure
the check is placed at the top of createRows and references the existing
createRows function signature.
| ...(showRetry | ||
| ? [ | ||
| { | ||
| label: "재도전하기", | ||
| onClick: () => { | ||
| setOpen(false); | ||
| onRetryClick?.(); | ||
| }, | ||
| }, | ||
| ] | ||
| : []), |
There was a problem hiding this comment.
Hide “재도전하기” when no retry handler is provided.
With showRetry=true and missing onRetryClick, users get a visible action that does nothing.
🔧 Proposed fix
- const menuItems = [
+ const shouldShowRetry = showRetry && typeof onRetryClick === "function";
+ const menuItems = [
{
label: "삭제하기",
onClick: () => {
setOpen(false);
onDeleteClick();
},
},
- ...(showRetry
+ ...(shouldShowRetry
? [
{
label: "재도전하기",
onClick: () => {
setOpen(false);
onRetryClick?.();
},
},
]
: []),
];🤖 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/mock-application/home/ApplicationKebabButton.tsx`
around lines 28 - 38, The retry menu item is being shown when showRetry is true
even if no handler is provided; update the conditional that builds the actions
array in ApplicationKebabButton (the block that currently checks showRetry) to
only include the "재도전하기" entry when showRetry is true AND onRetryClick is a
function (or non-null), so the menu item is omitted if onRetryClick is missing;
preserve the existing behavior of closing via setOpen(false) and calling
onRetryClick() when present.
| setShowDeleteConfirm(false); | ||
| setDeleteTargetApplication(null); | ||
| removeApplicationLocally(targetApplication); | ||
|
|
||
| try { | ||
| const deleted = await deleteApplicationRecord(); | ||
|
|
||
| if (deleted) { | ||
| closeDeleteConfirm(); | ||
| setShowDeleteToast(true); | ||
| } | ||
| await deleteJobPosting(targetApplication.jobPostingId); | ||
| setShowDeleteToast(true); | ||
| } catch (error) { | ||
| setApplicationsErrorMessage( | ||
| error instanceof Error | ||
| ? error.message | ||
| : "지원 기록을 삭제하지 못했습니다.", | ||
| ); |
There was a problem hiding this comment.
Avoid removing/caching the record before delete API success.
Line 219 removes the application locally before deleteJobPosting resolves. If the API fails on Lines 224-229, the UI/session cache stays deleted even though the backend record still exists.
Suggested fix
const targetApplication = deleteTargetApplication;
setIsDeleting(true);
setShowDeleteConfirm(false);
setDeleteTargetApplication(null);
- removeApplicationLocally(targetApplication);
try {
await deleteJobPosting(targetApplication.jobPostingId);
+ removeApplicationLocally(targetApplication);
+ setApplicationsErrorMessage("");
setShowDeleteToast(true);
} catch (error) {
setApplicationsErrorMessage(
error instanceof Error
? error.message
: "지원 기록을 삭제하지 못했습니다.",
);
} finally {
setIsDeleting(false);
}🤖 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/mock-application/MockApplicationHomePageClient.tsx`
around lines 217 - 229, The code currently calls
removeApplicationLocally(targetApplication) before awaiting deleteJobPosting,
which causes the UI/cache to drop the record even if the API delete fails;
change the flow so that deleteJobPosting(targetApplication.jobPostingId) is
awaited inside the try block first, then on success call
removeApplicationLocally(...) and setShowDeleteToast(true); on failure (catch)
do not remove from local state — instead setApplicationsErrorMessage(...) and
leave state intact (or re-add the application if you must keep the optimistic
removal), and still call setShowDeleteConfirm(false) and
setDeleteTargetApplication(null) as appropriate; update references to
setShowDeleteConfirm, setDeleteTargetApplication, removeApplicationLocally,
deleteJobPosting, setShowDeleteToast, and setApplicationsErrorMessage
accordingly.
| width: clamp(var(--width-lnb-min), 100%, var(--width-lnb)); | ||
| min-width: var(--width-lnb-min); | ||
| max-width: var(--width-lnb); | ||
| margin: 0 auto; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Check all .container-lnb declarations and possible breakpoint overrides:"
rg -n -C3 '\.container-lnb|`@container`|`@media`' --type=css
echo
echo "Expected: no small-breakpoint rule should keep min-width: 912px on .container-lnb."Repository: JobDri-Developer/FrontEnd
Length of output: 1584
Remove the hard minimum sizing on .container-lnb to prevent horizontal overflow on narrow widths.
.container-lnb sets width: clamp(var(--width-lnb-min), 100%, var(--width-lnb)) and min-width: var(--width-lnb-min), so when the available width drops below --width-lnb-min it will still be forced to that minimum; the @container content-frame-lnb (max-width: 911px) override only changes margin-inline and doesn’t address the sizing.
💡 Suggested fix
.container-lnb {
- width: clamp(var(--width-lnb-min), 100%, var(--width-lnb));
- min-width: var(--width-lnb-min);
+ width: min(100%, var(--width-lnb));
max-width: var(--width-lnb);
margin: 0 auto;
}📝 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.
| width: clamp(var(--width-lnb-min), 100%, var(--width-lnb)); | |
| min-width: var(--width-lnb-min); | |
| max-width: var(--width-lnb); | |
| margin: 0 auto; | |
| } | |
| .container-lnb { | |
| width: min(100%, var(--width-lnb)); | |
| max-width: var(--width-lnb); | |
| margin: 0 auto; | |
| } |
🤖 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/styles/grid.css` around lines 45 - 49, The .container-lnb rule
forces a hard minimum by using min-width: var(--width-lnb-min) alongside width:
clamp(...), causing horizontal overflow on narrow viewports; remove the
min-width declaration (or override it to min-width: 0 in the responsive
container query) so the clamp can actually shrink below --width-lnb-min. Update
the CSS rule for .container-lnb (or the `@container` content-frame-lnb override)
to eliminate the min-width restriction so the element can fit narrow screens.
🔗 관련 이슈
📝 개요
⌨️ 작업 상세 내용
useReApply연동jobPostingId누락으로 404가 발생하던 경로 보정💡 코드 설명 및 참고사항
📸 스크린샷 (UI 변경 시)
2026-05-29.002413.mp4
2026-05-29.002640.mp4
2026-05-29.002527.mp4
🔍 리뷰 요구사항 (Reviewers)
Summary by CodeRabbit
New Features
Style
Chores