Skip to content

[Feature/#140] 랜딩페이지 구현 및 로그인/대시보드 라우팅 안정화 - #164

Merged
Seojegyeong merged 20 commits into
developfrom
feature/#140
Apr 30, 2026
Merged

Seojegyeong merged 20 commits into
developfrom
feature/#140

Conversation

@Seojegyeong

@Seojegyeong Seojegyeong commented Apr 29, 2026

Copy link
Copy Markdown
Collaborator

🚨 관련 이슈

#140

✨ 변경사항

  • 🐞 BugFix Something isn't working
  • 💻 CrossBrowsing Browser compatibility
  • 🌏 Deploy Deploy
  • 🎨 Design Markup & styling
  • 📃 Docs Documentation writing and editing (README.md, etc.)
  • ✨ Feature Feature
  • [] 🔨 Refactor Code refactoring
  • ⚙️ Setting Development environment setup
  • ✅ Test Test related (storybook, jest, etc.)

✏️ 작업 내용

LandingPage 구현 + Motion

  • 랜딩 페이지 전체 구조 구현(섹션 구성: Hero / Features / Guide / Pricing / FAQ / BrandIdentity / Footer)
  • Framer Motion 적용: 섹션/카드 단위 진입 애니메이션(motion.div, useInView 포함)
  • 요금제 섹션 개선(4개 플랜 기준): 4개 카드 그리드/반응형 레이아웃 최적화

Routing / Auth

  • / 진입 시 /landing으로 이동하도록 설정
  • 로그인/소셜로그인 성공 시 /dashboard로 이동하도록 수정
  • 대시보드 기본 진입 경로를 /dashboard로 통일
  • 사이드바 “통합 대시보드” 클릭 시 랜딩으로 가던 문제 해결(경로/활성화 로직 수정)

Dev proxy

  • 웹 로그인 시 Invalid CORS request 발생 → Vite 프록시에서 Origin 헤더 제거로 해결
  • dev 환경에서 VITE_API_BASE_URL이 없더라도 상대경로 호출이 가능하도록 axiosInstance 설정 보완

스크린샷

CaptureX_2026-04-29_233315_localhost

😅 미완성 작업

N/A

📢 논의 사항 및 참고 사항

  • develop 병합 과정에서 충돌을 해결한 merge 커밋이 포함되어 있습니다.
  • header 로고 및 hero section 이미지 임시

💬 리뷰어 가이드 (P-Rules)
P1: 필수 반영 (Critical) - 버그 가능성, 컨벤션 위반. 해결 전 머지 불가.
P2: 적극 권장 (Recommended) - 더 나은 대안 제시. 가급적 반영 권장.
P3: 제안 (Suggestion) - 아이디어 공유. 반영 여부는 드라이버 자율.
P4: 단순 확인/칭찬 (Nit) - 사소한 오타, 칭찬 등 피드백.

Summary by CodeRabbit

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 전체 랜딩 페이지 추가 — 헤더, 히어로, 브랜드/기능/가이드/타임라인/요금제/FAQ, 푸터 포함
    • 가이드용 차트, 플랫폼 선택 UI, 타임라인 및 기타 랜딩 섹션 추가
  • 개선

    • 대시보드 라우팅을 /dashboard로 이동하고 루트는 랜딩으로 리다이렉트
    • 사이드바 활성 경로 판별 로직 개선
    • TrafficChart에 높이, 이상치 표시, Y축 최대값 옵션 추가
    • 개발 환경에서 API 기본 URL 처리 유연성 강화
    • 랜딩용 색상 테마 변수 및 스크롤바 스타일 보완
  • 버그 픽스

    • 로그인/리다이렉트 성공 후 대시보드로 이동하도록 수정

- 랜딩 섹션 로딩(Suspense) 분리로 초기 렌더 개선
- 요금제/플랫폼 선택 UI 디테일 정리
- '/' 접속 시 '/landing'으로 이동
- 미사용 에셋 제거 및 lockfile 동기화

Made-with: Cursor
- 헤더의 로그인/시작하기 버튼 제거
- 히어로 보조 CTA를 요금제 섹션 이동으로 변경

Made-with: Cursor
- 로그인/소셜 로그인 성공 후 '/dashboard'로 이동
- 대시보드/사이드바 경로를 '/dashboard'로 통일
- 개발 프록시에서 Origin 헤더 제거로 CORS 거부 방지
- dev 환경에서 API baseURL 미설정 허용

Made-with: Cursor
- LandingPage를 pages/landing으로 이동
- 라우터 import 경로 정리

Made-with: Cursor
@Seojegyeong Seojegyeong self-assigned this Apr 29, 2026
@Seojegyeong Seojegyeong added 🎨 Html&css 마크업 & 스타일링 ✨ Feature 기능 개발 labels Apr 29, 2026
@Seojegyeong Seojegyeong linked an issue Apr 29, 2026 that may be closed by this pull request
5 tasks
@coderabbitai

coderabbitai Bot commented Apr 29, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

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

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 96bbe85d-8970-42a3-9b5a-d796d9a41e4a

📥 Commits

Reviewing files that changed from the base of the PR and between 19ac006 and 11d9a89.

📒 Files selected for processing (10)
  • src/components/landing/LandingBrandIdentity.tsx
  • src/components/landing/LandingFAQ.tsx
  • src/components/landing/LandingFeatures.tsx
  • src/components/landing/LandingFooter.tsx
  • src/components/landing/LandingGuide.tsx
  • src/components/landing/LandingHeader.tsx
  • src/components/landing/LandingHero.tsx
  • src/components/landing/LandingPricing.tsx
  • src/components/landing/LandingSectionHeader.tsx
  • src/pages/landing/LandingPage.tsx
📝 Walkthrough

Walkthrough

루트 경로를 /landing으로 리다이렉트하도록 라우팅을 재구성하고, 대시보드의 기본 경로를 /에서 /dashboard로 이동시켰다. 랜딩 페이지 관련 13개 컴포넌트를 신규 추가했고, TrafficChart 컴포넌트를 props 기반으로 설정 가능하게 리팩토링했으며 로그인/리다이렉트 후 네비게이션을 /dashboard로 통일했다.

Changes

Cohort / File(s) Summary
랜딩 UI 컴포넌트
src/components/landing/LandingHeader.tsx, src/components/landing/LandingHero.tsx, src/components/landing/LandingBrandIdentity.tsx, src/components/landing/LandingFeatures.tsx, src/components/landing/LandingGuide.tsx, src/components/landing/LandingPricing.tsx, src/components/landing/LandingFAQ.tsx, src/components/landing/LandingFooter.tsx, src/components/landing/LandingSectionHeader.tsx
랜딩 페이지 섹션들을 담당하는 여러 React 컴포넌트 추가(헤더/히어로/브랜드/특징/가이드/요금제/FAQ/푸터 등). framer-motion 애니메이션과 접근성·반응형 레이아웃 적용.
가이드 서브컴포넌트
src/components/landing/GuideOverviewChart.tsx, src/components/landing/GuideTimeline.tsx, src/components/landing/GuidePlatform.tsx
가이드 섹션용 차트(react-apexcharts lazy import), 모의 타임라인 레이아웃, 플랫폼 선택 드롭다운 컴포넌트 추가. 일부 컴포넌트는 lazy/Suspense와 skeleton 처리 포함.
랜딩 페이지 및 라우트 등록
src/pages/landing/LandingPage.tsx, src/routes/Router.tsx, src/routes/MainRoutes.tsx, src/constants/sidebarNav.ts
LandingPage를 라우터에 lazy로 등록하고 루트(/)를 /landing으로 리다이렉트. Overview 대시보드 경로를 /에서 /dashboard로 변경하고, 사이드바 내비값도 동기화.
대시보드 차트 리팩토링
src/components/dashboard/charts/TrafficChart.tsx
TrafficChart가 props(yAxisMax?, height = 400, showAnomaly = true)를 수용하도록 변경. apexOptions를 useMemo로 계산하고 y-axis max 오버라이드 및 이상치/버블 표시를 showAnomaly로 제어.
인증 흐름 및 사이드바 경로 정규화
src/pages/auth/Login.tsx, src/pages/auth/RedirectPage.tsx, src/components/sidebar/Sidebar.tsx
로그인/리다이렉트 성공 후 목적지를 /dashboard로 변경. Sidebar는 pathname 정규화(후행 슬래시 제거) 및 /dashboard에 대한 정확한 매칭 로직으로 활성 상태 판정 수정.
스타일 및 설정 변경
src/index.css, src/lib/axiosInstance.ts
랜딩 타임라인 스크롤바 숨김 스타일과 랜딩 색상 변수 추가. Axios 초기화는 개발에서 VITE_API_BASE_URL 미설정 시 에러를 던지지 않도록 변경(프로덕션에서는 여전히 검사).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

Possibly related PRs

Suggested reviewers

  • jjjsun
🚥 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 제목은 전체 변경 사항의 핵심(랜딩페이지 구현 및 라우팅 안정화)을 명확하게 요약하고 있으며, 이슈 번호(#140)도 포함되어 있어 구체적이고 추적 가능합니다.
Description check ✅ Passed PR 설명이 템플릿 구조를 따르고 있으며, 관련 이슈(#140), 변경사항 체크박스, 상세한 작업 내용(LandingPage 구현, 라우팅/인증, Dev proxy), 스크린샷, 그리고 리뷰어 가이드가 모두 포함되어 있습니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 feature/#140

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
Review rate limit: 0/1 reviews remaining, refill in 38 minutes and 49 seconds.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Nitpick comments (4)
src/components/landing/LandingFooter.tsx (1)

29-31: 연도 하드코딩은 유지보수 포인트가 됩니다.

Line 30은 런타임 연도로 계산해두면 매년 수정 이슈를 줄일 수 있어요.

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

In `@src/components/landing/LandingFooter.tsx` around lines 29 - 31, In
LandingFooter.tsx replace the hard-coded "© 2026" string with a runtime computed
year by using JavaScript's Date().getFullYear() inside the LandingFooter
component (keep the existing <p className="font-caption text-text-disabled">
element and its text structure), e.g., build the string dynamically when
rendering so the footer shows "© {new Date().getFullYear()} WhereYouAd. All
rights reserved." to avoid manual yearly updates.
src/components/landing/GuidePlatform.tsx (1)

77-94: 드롭다운 트리거와 패널을 ARIA로 연결하면 더 좋습니다.

aria-expanded와 함께 aria-controls + 패널 id를 연결하면 보조기기 탐색성이 더 좋아집니다.

As per coding guidelines, src/**: 7. 접근성: 시맨틱 HTML, ARIA 속성 사용 확인.

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

In `@src/components/landing/GuidePlatform.tsx` around lines 77 - 94, The button
that toggles the dropdown (using setIsMenuOpen and aria-expanded={isMenuOpen})
should include an aria-controls attribute that references the panel element's
id; add a stable unique id for the menu panel (e.g., "guide-platform-menu" or
generated via React's useId/useRef) on the div that renders when isMenuOpen is
true, and set aria-controls on the button to that id so assistive tech can
associate the trigger (button with ChevronDown) with the panel; ensure the panel
id matches exactly and remains stable across renders.
src/components/landing/LandingGuide.tsx (1)

12-24: 페이지 렌더 타입을 판별 유니온으로 바꿔서 조합 오류를 컴파일 타임에 막아주세요.

지금 구조는 useOverview/useTimeline/usePlatform/image/alt가 모두 선택값이라 잘못된 조합(예: 이미지 렌더인데 alt 누락)을 타입으로 막지 못합니다.

리팩터링 예시
-type TGuidePage = {
+type TGuidePageBase = {
   number: string;
   label: string;
   title: string;
   description: string;
   steps: TGuideStep[];
-  image?: string;
-  alt?: string;
   reverse: boolean;
-  useOverview?: boolean;
-  useTimeline?: boolean;
-  usePlatform?: boolean;
 };
+
+type TGuidePage =
+  | (TGuidePageBase & { kind: "overview" })
+  | (TGuidePageBase & { kind: "timeline" })
+  | (TGuidePageBase & { kind: "platform" })
+  | (TGuidePageBase & { kind: "image"; image: string; alt: string });
@@
-                {page.useOverview ? (
+                {page.kind === "overview" ? (
                   <div className="p-0 bg-transparent">
                     <GuideOverviewChart />
                   </div>
-                ) : page.useTimeline ? (
+                ) : page.kind === "timeline" ? (
                   <div className="p-0 bg-transparent">
                     <GuideTimeline />
                   </div>
-                ) : page.usePlatform ? (
+                ) : page.kind === "platform" ? (
                   <div className="p-0 bg-transparent">
                     <GuidePlatform />
                   </div>
                 ) : (
                   <img
                     src={page.image}
                     alt={page.alt}

As per coding guidelines "src/: ... 4. 타입 안정성: TypeScript 타입의 명확성 확인." અને "src/: ... 7. 접근성: 시맨틱 HTML, ARIA 속성 사용 확인."

Also applies to: 143-159

src/components/landing/LandingFeatures.tsx (1)

15-20: TFeatureCardProps.delay는 현재 사용되지 않아 타입이 불필요하게 복잡합니다.

delay를 선언해두고 실제 데이터에서는 Omit으로 제거하고 있어요. 카드 데이터 전용 타입으로 단순화하면 타입 의도가 더 명확해집니다.

리팩터링 예시
-type TFeatureCardProps = {
-  delay: number;
+type TFeatureCardProps = {
   title: string;
   description: string;
   Graphic: () => ReactNode;
 };
@@
-  const featureCards: Omit<TFeatureCardProps, "delay">[] = [
+  const featureCards: TFeatureCardProps[] = [

As per coding guidelines "src/**: ... 4. 타입 안정성: TypeScript 타입의 명확성 확인."

Also applies to: 184-185

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

In `@src/components/landing/LandingFeatures.tsx` around lines 15 - 20,
TFeatureCardProps currently declares an unused delay field which complicates
types; remove delay from TFeatureCardProps and create a simplified Card data
type (or use the existing card array type directly) so the data model matches
usage, update any Omit<TFeatureCardProps, "delay"> usages to the new type, and
adjust the FeatureCard/landing card data declarations and consumers in
LandingFeatures.tsx (also address the duplicate issue around the other
occurrence referenced at lines 184-185) so the props and card data types are
consistent and minimal.
🤖 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/dashboard/charts/TrafficChart.tsx`:
- Around line 205-227: The current useMemo block that computes apexOptions
ignores yAxisMax when it is 0 because it uses if (!yAxisMax); change that guard
to only exclude null/undefined (e.g., use if (yAxisMax == null) or if (yAxisMax
=== undefined || yAxisMax === null)) so a numeric 0 will still override the
y-axis max; update the logic inside the useMemo where yAxisMax, chartOptions,
and local yaxis are referenced (apexOptions, useMemo, yAxisMax, chartOptions,
yaxis) accordingly.

In `@src/components/landing/GuideOverviewChart.tsx`:
- Around line 96-99: The chart currently defines two series (variable series
with names "클릭수" and "예측 클릭수") but the legend rendering only shows one item;
update the chart legend configuration to display both series names to match the
series array. Locate the variable series and the chart options where legend
items/labels are set (references: series, and the legend option used around the
chart render), then adjust the legend to include both "클릭수" and "예측 클릭수" (or
derive labels from series.map(s => s.name)) and ensure legend.show (or
equivalent) remains true so the legend entries align with the two series. Ensure
no hardcoded single-label remains (remove or replace any single-entry legend
array).

In `@src/components/landing/GuidePlatform.tsx`:
- Around line 98-114: The toggle button currently only updates visual styles;
add an accessibility state by exposing selection via an ARIA attribute: update
the button rendered in the map (the element using togglePlatform(platform.id),
platform.id and isSelected) to include aria-pressed={isSelected} so assistive
technologies can read the toggle state; ensure the boolean comes from the same
isSelected variable used for styling and keep the existing sr-only label
unchanged.

In `@src/components/landing/GuideTimeline.tsx`:
- Around line 80-86: The icon-only navigation buttons in GuideTimeline (the
buttons rendering ChevronLeftIcon and ChevronRightIcon) lack accessible names
and explicit button types; update each icon-only <button> (both the left/right
chevrons and the similar buttons later in the file) to include type="button" and
a descriptive aria-label (e.g., aria-label="Previous week" / aria-label="Next
week" or context-appropriate labels) so screen readers convey their purpose
while preserving existing classes and handlers.
- Around line 90-97: The two clickable divs in the GuideTimeline component that
wrap SortIcon and FilterIcon are non-semantic and block keyboard access; change
those divs to semantic <button> elements (preserve the className styling, add
type="button", keep any onClick handlers) and add accessible labels (e.g.,
aria-label or visible text is fine) so the Sort and Filter controls are
keyboard-focusable and screen-reader friendly; update the elements that
currently render SortIcon and FilterIcon in GuideTimeline accordingly.

In `@src/components/landing/LandingFeatures.tsx`:
- Around line 77-109: The two decorative controls in LandingFeatures (the
gradient "AI로 요약하기" button with the animated motion.span and the "다운로드" button)
are non-interactive visual-only elements but are rendered as focusable
<button>s; change them to non-interactive elements or remove them from the
keyboard/AT tree: replace the decorative <button> elements with <div> or <span>
and add role="presentation" and aria-hidden="true", or if you must keep
<button>, set tabIndex={-1} and aria-hidden="true" (or disabled for semantic
controls) to prevent keyboard focus; apply the same fix for the similar controls
referenced at the other occurrence (the elements around symbols SparkleIcon and
the styled motion.span) so decorative UI is not tabbable.

In `@src/components/landing/LandingFooter.tsx`:
- Around line 14-25: The footer Link elements in LandingFooter.tsx currently use
placeholder hrefs ("#") so the core links don't navigate; update each Link (the
four Link elements rendering 회사소개, 이용약관, 개인정보처리방침, 고객센터) to point to the actual
internal routes or external URLs (e.g., Link to="/about" for 회사소개, to="/terms"
for 이용약관, to="/privacy" for 개인정보처리방침, and to="/support" or an external support
URL for 고객센터), ensuring you use the same Link component import
(react-router-dom) and preserve the existing className and accessibility (add
aria-labels if needed).

In `@src/components/landing/LandingPricing.tsx`:
- Around line 179-187: The CTA button in LandingPricing rendering (the button
using plan.buttonText and plan.featured) has no click handler; wire it to the
plan's action by using the plan's CTA field (e.g., plan.ctaUrl or
plan.ctaAction) — if plan.ctaUrl exists render the button as a link/navigation
(or add an onClick that calls a navigate function/router push or window.open for
external URLs), fall back to a provided plan.onClick callback when present, and
preserve the existing styling for plan.featured; also ensure the handler
respects target behavior (same tab vs new tab) and adds an aria-label for
accessibility.

In `@src/components/sidebar/Sidebar.tsx`:
- Around line 82-94: The dashboard active-check logic (used in the child loop
and in isParentActive) fails to treat "/dashboard/" as equal to "/dashboard";
normalize location.pathname and item/c.path comparisons by trimming trailing
slashes before comparing (e.g., derive a normalizedPath =
location.pathname.replace(/\/+$/, '') and compare normalizedPath ===
'/dashboard' or normalizedPath.startsWith(item.path.replace(/\/+$/, ''))), then
use those normalized comparisons in the existing functions/conditions
(references: isParentActive, the c.path === "/dashboard" equality check and the
location.pathname.startsWith(c.path) usage) so "/dashboard/" is correctly
treated as active.

---

Nitpick comments:
In `@src/components/landing/GuidePlatform.tsx`:
- Around line 77-94: The button that toggles the dropdown (using setIsMenuOpen
and aria-expanded={isMenuOpen}) should include an aria-controls attribute that
references the panel element's id; add a stable unique id for the menu panel
(e.g., "guide-platform-menu" or generated via React's useId/useRef) on the div
that renders when isMenuOpen is true, and set aria-controls on the button to
that id so assistive tech can associate the trigger (button with ChevronDown)
with the panel; ensure the panel id matches exactly and remains stable across
renders.

In `@src/components/landing/LandingFeatures.tsx`:
- Around line 15-20: TFeatureCardProps currently declares an unused delay field
which complicates types; remove delay from TFeatureCardProps and create a
simplified Card data type (or use the existing card array type directly) so the
data model matches usage, update any Omit<TFeatureCardProps, "delay"> usages to
the new type, and adjust the FeatureCard/landing card data declarations and
consumers in LandingFeatures.tsx (also address the duplicate issue around the
other occurrence referenced at lines 184-185) so the props and card data types
are consistent and minimal.

In `@src/components/landing/LandingFooter.tsx`:
- Around line 29-31: In LandingFooter.tsx replace the hard-coded "© 2026" string
with a runtime computed year by using JavaScript's Date().getFullYear() inside
the LandingFooter component (keep the existing <p className="font-caption
text-text-disabled"> element and its text structure), e.g., build the string
dynamically when rendering so the footer shows "© {new Date().getFullYear()}
WhereYouAd. All rights reserved." to avoid manual yearly updates.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 52f0c710-457c-4ef6-9b20-3218c3ff8500

📥 Commits

Reviewing files that changed from the base of the PR and between d0af00d and 21b208d.

⛔ Files ignored due to path filters (26)
  • package-lock.json is excluded by !**/package-lock.json and included by none
  • package.json is excluded by none and included by none
  • src/assets/icon/ai/sparkle.svg is excluded by !**/*.svg and included by src/**
  • src/assets/icon/chevron/chervon-double-right.svg is excluded by !**/*.svg and included by src/**
  • src/assets/icon/chevron/chervon-left.svg is excluded by !**/*.svg and included by src/**
  • src/assets/icon/chevron/chevron-down.svg is excluded by !**/*.svg and included by src/**
  • src/assets/icon/chevron/chevron-up.svg is excluded by !**/*.svg and included by src/**
  • src/assets/icon/chevron/trend-down.svg is excluded by !**/*.svg and included by src/**
  • src/assets/icon/chevron/trend-up.svg is excluded by !**/*.svg and included by src/**
  • src/assets/icon/timeline/chevron-left.svg is excluded by !**/*.svg and included by src/**
  • src/assets/icon/timeline/chevron-right.svg is excluded by !**/*.svg and included by src/**
  • src/assets/icon/timeline/filter.svg is excluded by !**/*.svg and included by src/**
  • src/assets/icon/timeline/kebab.svg is excluded by !**/*.svg and included by src/**
  • src/assets/icon/timeline/sort.svg is excluded by !**/*.svg and included by src/**
  • src/assets/logo/social-logo/plain/google_ads.png is excluded by !**/*.png and included by src/**
  • src/assets/logo/social-logo/plain/meta.svg is excluded by !**/*.svg and included by src/**
  • src/assets/logo/social-logo/wordmark/naver-wordmark.png is excluded by !**/*.png and included by src/**
  • src/assets/logo/social-logo/wordmark/naver-wordmark.svg is excluded by !**/*.svg and included by src/**
  • src/assets/mockup/iOS app dock.png is excluded by !**/*.png and included by src/**
  • src/assets/mockup/iPad Air mockup.png is excluded by !**/*.png and included by src/**
  • src/assets/mockup/laptop_mockup.png is excluded by !**/*.png and included by src/**
  • src/assets/mockup/logo_test/logo_2.png is excluded by !**/*.png and included by src/**
  • src/assets/mockup/optimized/mockup_test.jpg is excluded by !**/*.jpg and included by src/**
  • src/assets/mockup/optimized/timeline_dashboard.jpg is excluded by !**/*.jpg and included by src/**
  • tsconfig.app.json is excluded by none and included by none
  • vite.config.ts is excluded by none and included by none
📒 Files selected for processing (22)
  • src/components/dashboard/charts/TrafficChart.tsx
  • src/components/landing/GuideOverviewChart.tsx
  • src/components/landing/GuidePlatform.tsx
  • src/components/landing/GuideTimeline.tsx
  • src/components/landing/LandingBrandIdentity.tsx
  • src/components/landing/LandingFAQ.tsx
  • src/components/landing/LandingFeatures.tsx
  • src/components/landing/LandingFooter.tsx
  • src/components/landing/LandingGuide.tsx
  • src/components/landing/LandingHeader.tsx
  • src/components/landing/LandingHero.tsx
  • src/components/landing/LandingPricing.tsx
  • src/components/landing/LandingSectionHeader.tsx
  • src/components/sidebar/Sidebar.tsx
  • src/constants/sidebarNav.ts
  • src/index.css
  • src/lib/axiosInstance.ts
  • src/pages/auth/Login.tsx
  • src/pages/auth/RedirectPage.tsx
  • src/pages/landing/LandingPage.tsx
  • src/routes/MainRoutes.tsx
  • src/routes/Router.tsx

Comment thread src/components/dashboard/charts/TrafficChart.tsx
Comment thread src/components/landing/GuideOverviewChart.tsx
Comment thread src/components/landing/GuidePlatform.tsx
Comment thread src/components/landing/GuideTimeline.tsx
Comment thread src/components/landing/GuideTimeline.tsx
Comment thread src/components/landing/LandingFeatures.tsx Outdated
Comment thread src/components/landing/LandingFooter.tsx Outdated
Comment thread src/components/landing/LandingPricing.tsx
Comment thread src/components/sidebar/Sidebar.tsx Outdated
CI의 pnpm --frozen-lockfile 설치 실패를 방지하기 위해
package.json 변경사항을 pnpm-lock.yaml에 반영합니다.

Made-with: Cursor
- 미사용 패키지(lucide-react) 제거
- pnpm-lock.yaml / package-lock.json 동기화

Made-with: Cursor
@github-actions

github-actions Bot commented Apr 29, 2026

Copy link
Copy Markdown

📚 Storybook 배포 완료

항목 링크
📖 Storybook https://69a147b60a56365d9e2185ef-haueqywdxo.chromatic.com/
🔍 Chromatic https://www.chromatic.com/build?appId=69a147b60a56365d9e2185ef&number=210

- 데코용 폼 컨트롤을 비상호작용 요소로 변경해 포커스 제거
- 대시보드 메뉴 활성화 판정에서 trailing slash 처리
- 요금제 CTA 버튼에 회원가입/문의 동작 연결
- 차트 시리즈/범례 불일치 수정

Made-with: Cursor
- 프로 플랜 문의 CTA mailto를 whereyouadofficial@gmail.com으로 변경

Made-with: Cursor
- 초기 단계에 필요한 링크(이용약관/개인정보처리방침/고객센터)만 유지

Made-with: Cursor
- 고객센터를 mailto(whereyouadofficial@gmail.com)로 연결
- 약관/개인정보처리방침은 링크 준비 전까지 비활성 텍스트로 표시

Made-with: Cursor
- 이용약관/개인정보처리방침을 Notion 링크로 연결
- 고객센터 mailto 유지

Made-with: Cursor
@Seojegyeong
Seojegyeong requested review from YermIm and jjjsun April 29, 2026 15:43

@jjjsun jjjsun left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

P3: 랜딩헤더부분 높이랑 폰트크기 조금 더 키우면 더 잘보일것같습니다!

@jjjsun

jjjsun commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

P4: 전체적인 구조가 깔끔하게 잘 정리된것같아요! 고생하셨어요!

- 헤더 높이를 72px로 고정해 OS/브라우저별 차이를 최소화
- 히어로 높이 계산에 CSS 변수를 사용해 레이아웃 일관성 유지

Made-with: Cursor
- md 이상에서 헤더 높이를 80px로 상향
- 헤더 네비게이션 폰트 크기 15px → 16px

Made-with: Cursor

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/components/landing/LandingPricing.tsx (1)

106-115: ⚡ Quick win

CTA 분기 기준을 플랜 name 문자열에서 분리해 주세요.

지금은 "프로" 텍스트에 비즈니스 로직이 묶여 있어 문구 변경/다국어 시 동작이 깨질 수 있습니다. ctaType/ctaHref 같은 명시 필드를 plans에 두고 분기하는 쪽이 안전합니다.

제안 수정안
 type TPlan = {
   name: string;
+  ctaType: "signup" | "mailto";
+  ctaHref?: string;
   target: string;
   price: string;
@@
   {
     name: "프리",
+    ctaType: "signup",
@@
   {
     name: "스타터",
+    ctaType: "signup",
@@
   {
     name: "팀",
+    ctaType: "signup",
@@
   {
     name: "프로",
+    ctaType: "mailto",
+    ctaHref: "mailto:whereyouadofficial@gmail.com",
@@
-  function handleCta(planName: string) {
-    if (planName === "프로") {
+  function handleCta(plan: TPlan) {
+    if (plan.ctaType === "mailto" && plan.ctaHref) {
       const subject = encodeURIComponent("WhereYouAd 요금제 문의");
       const body = encodeURIComponent("문의하실 내용을 입력해 주세요.");
-      window.location.href = `mailto:whereyouadofficial@gmail.com?subject=${subject}&body=${body}`;
+      window.location.href = `${plan.ctaHref}?subject=${subject}&body=${body}`;
       return;
     }
@@
-                onClick={() => handleCta(plan.name)}
+                onClick={() => handleCta(plan)}

As per coding guidelines "2. 구조와 책임 분리: 페이지에 비즈니스 로직이 과도하지 않은지 확인. 커스텀 훅으로의 분리 여부 검토."

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

In `@src/components/landing/LandingPricing.tsx` around lines 106 - 115, The CTA
branching in handleCta currently depends on the plan name string ("프로"); change
the plans data to include explicit CTA metadata (e.g., add ctaType: "mailto" |
"signup" and optional ctaHref or ctaSubject/ctaBody fields to each plan) and
update handleCta to switch on that ctaType instead of planName—use ctaHref or
construct the mailto from ctaSubject/ctaBody when ctaType === "mailto", and
navigate("/signup") (or use ctaHref) when ctaType === "signup"; update any
callers that pass plan info to use the new fields and keep function name
handleCta as the single location for this behavior.
🤖 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/landing/LandingHero.tsx`:
- Around line 64-75: The decorative ChevronDown icon in LandingHero.tsx is
exposed to assistive tech; make it ignored by screen readers by adding ARIA
attributes—set aria-hidden="true" and focusable="false" on the icon element (or
its immediate wrapper) where ChevronDown is rendered inside the motion.div so
the decorative chevron is removed from the accessibility tree while preserving
visuals and animation.

---

Nitpick comments:
In `@src/components/landing/LandingPricing.tsx`:
- Around line 106-115: The CTA branching in handleCta currently depends on the
plan name string ("프로"); change the plans data to include explicit CTA metadata
(e.g., add ctaType: "mailto" | "signup" and optional ctaHref or
ctaSubject/ctaBody fields to each plan) and update handleCta to switch on that
ctaType instead of planName—use ctaHref or construct the mailto from
ctaSubject/ctaBody when ctaType === "mailto", and navigate("/signup") (or use
ctaHref) when ctaType === "signup"; update any callers that pass plan info to
use the new fields and keep function name handleCta as the single location for
this behavior.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8ae0c50c-13ed-4ac4-bbac-994f44b14d59

📥 Commits

Reviewing files that changed from the base of the PR and between 21b208d and 19ac006.

⛔ Files ignored due to path filters (3)
  • package-lock.json is excluded by !**/package-lock.json and included by none
  • package.json is excluded by none and included by none
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !pnpm-lock.yaml and included by none
📒 Files selected for processing (8)
  • src/components/landing/GuideOverviewChart.tsx
  • src/components/landing/LandingFeatures.tsx
  • src/components/landing/LandingFooter.tsx
  • src/components/landing/LandingHeader.tsx
  • src/components/landing/LandingHero.tsx
  • src/components/landing/LandingPricing.tsx
  • src/components/sidebar/Sidebar.tsx
  • src/pages/landing/LandingPage.tsx
✅ Files skipped from review due to trivial changes (1)
  • src/components/landing/GuideOverviewChart.tsx
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/components/landing/LandingFooter.tsx
  • src/pages/landing/LandingPage.tsx
  • src/components/sidebar/Sidebar.tsx
  • src/components/landing/LandingHeader.tsx
  • src/components/landing/LandingFeatures.tsx

Comment thread src/components/landing/LandingHero.tsx
랜딩 섹션의 카드 shadow/텍스트 톤을 통일하고 CTA/내비/FAQ에 focus-visible 상태를 추가했습니다.
기능 섹션 소제목은 font-weight 충돌을 고려해 강조를 확실히 했고, 히어로 스크롤 아이콘은 장식 요소로 접근성 트리에서 제외했습니다.

Made-with: Cursor
가이드 섹션 설명 문구를 줄바꿈 포함 텍스트로 변경하고, 렌더링을 위해 whitespace-pre-line을 적용했습니다.

Made-with: Cursor

@YermIm YermIm left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

P4: 깔끔하게 구현 잘하신 것 같습니다!! 수고하셨습니다 :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 기능 개발 🎨 Html&css 마크업 & 스타일링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

✨ [Feature] Landing Page 구현

3 participants