랜딩페이지#520
Conversation
Walkthrough이 PR은 기존의 모놀리식 Possibly related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
bb65bb8 to
03b9c1d
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/app/page.tsx (1)
70-76:⚠️ Potential issue | 🟠 Major | ⚡ Quick win불필요한
searchParams의존 제거로 페이지 정적 최적화 복구 필요
src/app/page.tsx(70-76)에서searchParams를await하지만 이후params를 사용하지 않습니다.- Next.js App Router에서는
searchParams를 사용하는 것만으로도 라우트가 동적 렌더링으로 옵트인되어 정적 생성이 디옵트됩니다.Page시그니처에서searchParams와const params = await searchParams;를 제거하세요. 쿼리값이 필요하다면useSearchParams(Client 컴포넌트) 또는 동적 라우트로 분리하는 방식이 맞습니다.🤖 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 `@src/app/page.tsx` around lines 70 - 76, The Page function currently declares and awaits searchParams (function Page and const params = await searchParams) but never uses params, which forces dynamic rendering; remove the searchParams parameter from the Page signature and delete the line "const params = await searchParams;" to restore static optimization, and if query values are required later convert to a client component using useSearchParams or a dedicated dynamic route instead.
🧹 Nitpick comments (1)
src/components/layout/Landing/LandingHeader.tsx (1)
14-23: ⚡ Quick winGoogle OAuth 리다이렉트 로직을 공통화해주세요.
동일한
${baseUrl}/oauth2/authorization/google조립/이동 로직이LandingHeader,LandingFooter,GoogleLoginButton에 중복되어 있고, 누락 env 처리도 이미 다르게 동작합니다. 공통 함수(또는GoogleLoginButton재사용)로 모아 드리프트를 막는 게 좋습니다.🤖 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 `@src/components/layout/Landing/LandingHeader.tsx` around lines 14 - 23, Duplicate Google OAuth redirect assembly/redirect logic across LandingHeader.handleStart, LandingFooter, and GoogleLoginButton should be centralized; create a shared helper (e.g., getGoogleOAuthUrl or redirectToGoogleOAuth) that reads NEXT_PUBLIC_BASE_API_URL once, throws or returns a Result/error when missing, and returns the full URL (`${baseUrl}/oauth2/authorization/google`) or performs the window.location.href change. Replace handleStart and other inline implementations to call this helper (or reuse GoogleLoginButton) so env missing handling is consistent and the redirect URL assembly is not duplicated.
🤖 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 `@src/components/layout/Landing/FAQItem.tsx`:
- Around line 10-30: The root element of the FAQItem component should be changed
from a <div> to an <li> to preserve list semantics when this component is
rendered inside a <ul>; update the JSX root element (the element wrapping the
button and the answer container in the FAQItem component) to <li> and keep all
existing attributes and className values (including aria-expanded on the button
and the grid/overflow structure) so behavior and styling remain unchanged;
ensure there are no invalid nested list/interactive element rules (button stays
as a child of the new <li>) and run the app’s linter/HTML validator to confirm
semantics are fixed.
In `@src/components/layout/Landing/FeatureCard.tsx`:
- Line 23: The Image components using the next/image "fill" prop should include
a responsive sizes prop to avoid oversized image selection; update the Image
usages in FeatureCard (component FeatureCard), ExperienceItem (ExperienceItem),
HowUseItem (HowUseItem), LinkThumbnailTitleSection (component
LinkThumbnailTitleSection) and AddMultiLinks (AddMultiLinks) to add a sizes
string matching the layout (for example: mobile ~100vw, tablet ~50vw, desktop
~33vw) so the browser can pick appropriately sized images for each breakpoint.
In `@src/components/wrappers/ChromeButton.tsx`:
- Around line 18-25: The ChromeButton component is showing google-icon.png while
its text and behavior target the Chrome Web Store; update the Image usage in
ChromeButton (the Image component instance) to use the correct Chrome icon asset
(e.g., change src from "google-icon.png" to the Chrome asset name such as
"chrome-icon.png"), keep a matching alt like "Chrome 로고", and ensure the
referenced chrome icon file exists in the public/images assets so the button
shows the proper Chrome icon.
In `@src/components/wrappers/GoogleLoginButton.tsx`:
- Around line 16-18: The button in the GoogleLoginButton component is missing an
explicit type which can cause it to act as a form submitter; update the JSX for
the button that calls handleGoogleLogin to include type="button" so it won't
trigger form submission (i.e., modify the <button ...> in GoogleLoginButton.tsx
that uses handleGoogleLogin to add the type attribute).
---
Outside diff comments:
In `@src/app/page.tsx`:
- Around line 70-76: The Page function currently declares and awaits
searchParams (function Page and const params = await searchParams) but never
uses params, which forces dynamic rendering; remove the searchParams parameter
from the Page signature and delete the line "const params = await searchParams;"
to restore static optimization, and if query values are required later convert
to a client component using useSearchParams or a dedicated dynamic route
instead.
---
Nitpick comments:
In `@src/components/layout/Landing/LandingHeader.tsx`:
- Around line 14-23: Duplicate Google OAuth redirect assembly/redirect logic
across LandingHeader.handleStart, LandingFooter, and GoogleLoginButton should be
centralized; create a shared helper (e.g., getGoogleOAuthUrl or
redirectToGoogleOAuth) that reads NEXT_PUBLIC_BASE_API_URL once, throws or
returns a Result/error when missing, and returns the full URL
(`${baseUrl}/oauth2/authorization/google`) or performs the window.location.href
change. Replace handleStart and other inline implementations to call this helper
(or reuse GoogleLoginButton) so env missing handling is consistent and the
redirect URL assembly is not duplicated.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 235d7e0e-4f81-4b90-a3ce-c024fc387977
⛔ Files ignored due to path filters (14)
public/images/landing-1.pngis excluded by!**/*.pngpublic/images/landing-2.pngis excluded by!**/*.pngpublic/images/landing-3.pngis excluded by!**/*.pngpublic/images/landing-4.pngis excluded by!**/*.pngpublic/images/landing-5.pngis excluded by!**/*.pngpublic/images/landing-6.pngis excluded by!**/*.pngpublic/images/landing-7.pngis excluded by!**/*.pngpublic/images/landing-add.pngis excluded by!**/*.pngpublic/images/landing-ai.pngis excluded by!**/*.pngpublic/images/landing-chatbot.pngis excluded by!**/*.pngpublic/images/landing-extension.pngis excluded by!**/*.pngpublic/images/landing_icon_bookmark.pngis excluded by!**/*.pngpublic/images/landing_icon_questionmark.pngis excluded by!**/*.pngpublic/images/landing_icon_searchoff.pngis excluded by!**/*.png
📒 Files selected for processing (15)
src/app/LandingPage.tsxsrc/app/layout-client.tsxsrc/app/page.tsxsrc/components/Icons/icons.tssrc/components/layout/Landing/ExperienceItem.tsxsrc/components/layout/Landing/FAQItem.tsxsrc/components/layout/Landing/FeatureCard.tsxsrc/components/layout/Landing/FeatureSection.tsxsrc/components/layout/Landing/HeroSection.tsxsrc/components/layout/Landing/HowUseItem.tsxsrc/components/layout/Landing/LandingFooter.tsxsrc/components/layout/Landing/LandingHeader.tsxsrc/components/layout/Landing/ScrollStackedCards.tsxsrc/components/wrappers/ChromeButton.tsxsrc/components/wrappers/GoogleLoginButton.tsx
💤 Files with no reviewable changes (1)
- src/app/LandingPage.tsx
| <div className="w-full rounded-[20px] bg-[linear-gradient(180deg,#F5F6FA_0%,#EAEDFF_100%)] px-13 py-12"> | ||
| <button | ||
| type="button" | ||
| aria-expanded={isOpen} | ||
| onClick={() => setIsOpen(prev => !prev)} | ||
| className="flex w-full cursor-pointer items-center justify-between text-left" | ||
| > | ||
| <span className="text-[20px] font-semibold md:text-[32px]">Q. {title}</span> | ||
| <SVGIcon icon={isOpen ? 'IC_Up' : 'IC_Down'} size="2xl" /> | ||
| </button> | ||
| <div | ||
| className={`grid transition-[grid-template-rows] duration-300 ease-in-out ${ | ||
| isOpen ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]' | ||
| }`} | ||
| > | ||
| <div className="overflow-hidden"> | ||
| <span className="block pt-4 text-[20px] leading-[160%] md:text-[32px]">{content}</span> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| ); |
There was a problem hiding this comment.
FAQ 항목 루트 태그를 <li>로 바꿔 목록 시맨틱을 맞춰주세요
현재 컴포넌트가 <ul> 내부에서 렌더링되는데 루트가 <div>라서 HTML 시맨틱이 깨집니다. 루트를 <li>로 바꾸는 게 안전합니다.
제안 수정안
- <div className="w-full rounded-[20px] bg-[linear-gradient(180deg,`#F5F6FA_0`%,`#EAEDFF_100`%)] px-13 py-12">
+ <li className="w-full rounded-[20px] bg-[linear-gradient(180deg,`#F5F6FA_0`%,`#EAEDFF_100`%)] px-13 py-12">
@@
- </div>
+ </li>🤖 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 `@src/components/layout/Landing/FAQItem.tsx` around lines 10 - 30, The root
element of the FAQItem component should be changed from a <div> to an <li> to
preserve list semantics when this component is rendered inside a <ul>; update
the JSX root element (the element wrapping the button and the answer container
in the FAQItem component) to <li> and keep all existing attributes and className
values (including aria-expanded on the button and the grid/overflow structure)
so behavior and styling remain unchanged; ensure there are no invalid nested
list/interactive element rules (button stays as a child of the new <li>) and run
the app’s linter/HTML validator to confirm semantics are fixed.
| className={`${bgClassName} flex h-[60vh] flex-col items-center gap-10 rounded-[20px] px-[55px] py-18 shadow-xl md:flex-row`} | ||
| > | ||
| <div className="relative aspect-700/337 w-full max-w-[700px]"> | ||
| <Image src={image} alt={imageAlt} fill /> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# fill 사용 Image 중 sizes 누락 위치 점검
rg -nP --type=tsx '<Image(?:(?!>).)*\bfill\b(?:(?!>).)*(?=>)' -g '!**/*.test.tsx'
rg -nP --type=tsx '<Image(?:(?!>).)*\bfill\b(?:(?!>).)*(?=>)' -g '!**/*.test.tsx' | rg -v '\bsizes='Repository: Team-SoFa/linkiving
Length of output: 119
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) FeatureCard.tsx 주변 확인
echo "---- FeatureCard.tsx (context around line 23) ----"
nl -ba src/components/layout/Landing/FeatureCard.tsx | sed -n '15,35p' || true
# 2) src 전체에서 <Image ... fill ...> 이지만 같은 태그에 sizes= 없는 경우(단일 라인 기준)
echo "---- <Image ... fill ...> without sizes= (single-line elements, src/**.tsx) ----"
rg -n --glob '!**/*.test.tsx' --glob '*.tsx' -S '<Image[^>]*\bfill\b' src \
| rg -v 'sizes=' || true
# 3) 혹시 fill/sizes가 여러 줄로 나뉘는 경우를 대비해, fill 라인만 먼저 수집
echo "---- Lines containing fill in TSX (for manual spot check) ----"
rg -n --glob '!**/*.test.tsx' --glob '*.tsx' -S '\bfill\b' src \
| head -n 50 || trueRepository: Team-SoFa/linkiving
Length of output: 2189
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) FeatureCard.tsx 주변 확인
echo "---- FeatureCard.tsx (context around line 23) ----"
nl -ba src/components/layout/Landing/FeatureCard.tsx | sed -n '15,35p' || true
# 2) src 전체에서 <Image ... fill ...> 이지만 같은 태그에 sizes= 없는 경우(단일 라인 기준)
echo "---- <Image ... fill ...> without sizes= (single-line elements, src/**.tsx) ----"
rg -n --glob '!**/*.test.tsx' --glob '*.tsx' -S '<Image[^>]*\bfill\b' src \
| rg -v 'sizes=' || true
# 3) 혹시 fill/sizes가 여러 줄로 나뉘는 경우를 대비해, fill 라인만 먼저 수집
echo "---- Lines containing fill in TSX (for manual spot check) ----"
rg -n --glob '!**/*.test.tsx' --glob '*.tsx' -S '\bfill\b' src \
| head -n 50 || trueRepository: Team-SoFa/linkiving
Length of output: 2189
fill 사용하는 next/image에 sizes를 추가해주세요
fill만 있고 sizes가 없으면 과도한 크기의 이미지를 선택해 랜딩/썸네일 성능에 불리할 수 있습니다. (다음 위치에 동일 패턴이 보입니다)
src/components/layout/Landing/FeatureCard.tsx:23src/components/layout/Landing/ExperienceItem.tsx:15src/components/layout/Landing/HowUseItem.tsx:15src/components/layout/SideNavigation/components/MenuSection/AddLink/LinkThumbnailTitleSection.tsx:46src/components/layout/SideNavigation/components/MenuSection/AddLink/AddMultiLinks.tsx:236
제안 수정안
- <Image src={image} alt={imageAlt} fill />
+ <Image
+ src={image}
+ alt={imageAlt}
+ fill
+ sizes="(min-width: 1024px) 700px, 100vw"
+ />📝 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.
| <Image src={image} alt={imageAlt} fill /> | |
| <Image | |
| src={image} | |
| alt={imageAlt} | |
| fill | |
| sizes="(min-width: 1024px) 700px, 100vw" | |
| /> |
🤖 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 `@src/components/layout/Landing/FeatureCard.tsx` at line 23, The Image
components using the next/image "fill" prop should include a responsive sizes
prop to avoid oversized image selection; update the Image usages in FeatureCard
(component FeatureCard), ExperienceItem (ExperienceItem), HowUseItem
(HowUseItem), LinkThumbnailTitleSection (component LinkThumbnailTitleSection)
and AddMultiLinks (AddMultiLinks) to add a sizes string matching the layout (for
example: mobile ~100vw, tablet ~50vw, desktop ~33vw) so the browser can pick
appropriately sized images for each breakpoint.
| <Image | ||
| src="/images/google-icon.png" | ||
| alt="Chrome 로고" | ||
| width={20} | ||
| height={20} | ||
| className="mr-2 inline-block" | ||
| /> | ||
| <span>Chrome 웹스토어 추가</span> |
There was a problem hiding this comment.
Chrome CTA에 Google 아이콘이 노출되고 있습니다.
버튼 문구/동작은 Chrome 웹스토어인데 아이콘이 google-icon.png라 의미가 어긋납니다. Chrome 아이콘 에셋으로 교체하는 게 맞습니다.
🤖 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 `@src/components/wrappers/ChromeButton.tsx` around lines 18 - 25, The
ChromeButton component is showing google-icon.png while its text and behavior
target the Chrome Web Store; update the Image usage in ChromeButton (the Image
component instance) to use the correct Chrome icon asset (e.g., change src from
"google-icon.png" to the Chrome asset name such as "chrome-icon.png"), keep a
matching alt like "Chrome 로고", and ensure the referenced chrome icon file exists
in the public/images assets so the button shows the proper Chrome icon.
| <button onClick={handleGoogleLogin} className=""> | ||
| Google 계정으로 계속하기 | ||
| </button> |
There was a problem hiding this comment.
버튼 type을 명시해주세요.
type이 없으면 폼 컨텍스트에서 기본 submit으로 동작할 수 있습니다. type="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 `@src/components/wrappers/GoogleLoginButton.tsx` around lines 16 - 18, The
button in the GoogleLoginButton component is missing an explicit type which can
cause it to act as a form submitter; update the JSX for the button that calls
handleGoogleLogin to include type="button" so it won't trigger form submission
(i.e., modify the <button ...> in GoogleLoginButton.tsx that uses
handleGoogleLogin to add the type attribute).
관련 이슈
PR 설명