Skip to content

[Feat] #17 - Navigation 컴포넌트 구현#51

Merged
kimsman06 merged 7 commits into
devfrom
feat/navigation-bar
Mar 18, 2026
Merged

[Feat] #17 - Navigation 컴포넌트 구현#51
kimsman06 merged 7 commits into
devfrom
feat/navigation-bar

Conversation

@kimsman06
Copy link
Copy Markdown
Collaborator

@kimsman06 kimsman06 commented Mar 12, 2026

[Feat] #17 - Navigation 컴포넌트 구현

🔎 What is this PR?

피그마 디자인 기반 네비게이션 컴포넌트를 shared/ui 레이어에 구현했습니다.


📝 Changes

  • 공통 Navigation 컴포넌트 구현 (src/shared/ui/navigation)
    • 가로 너비 1440px 고정 및 중앙 정렬 (내부 여백 제거 스펙 준수)
    • 피그마 기반 타이포그래피(16px, 자간 -0.4px, 줄높이 1.5) 및 로고 스타일 반영
    • shared/ui/button 및 ajou-logo.svg 자산 활용
  • 사용자 권한 기반 기능 제어
    • 어드민 권한(isAdmin: true) 보유 사용자에게만 관리자 모드 토글 스위치 노출
    • 관리자 모드 활성 시 드롭다운 내 '관리자 대시보드' 메뉴 동적 노출
    • 토글 스위치 배경색 및 핸들 이동 애니메이션(300ms, ease-in-out) 적용
  • 유저 인터페이스 및 인터랙션
    • 프로필 드롭다운(이름, 이메일, 유저타입 뱃지) 및 외부 클릭 시 닫기 로직 구현
    • 로그아웃 버튼 호버 스타일을 유저 아이콘과 동일하게 블루 톤으로 통일
    • shared/ui/icons에 LogOutIcon 신규 추가

📸 Screenshots

  • Storybook에서 다음 항목 확인 가능:
    • LoggedOut: 비로그인 상태 UI
    • StudentAdmin: 어드민 권한 학생 (토글 노출)
    • GeneralStudent: 일반 학생 (토글 미노출)
    • ProfessorAdmin: 어드민 권한 교수 (관리 모드 활성 상태)

📚 Background / Context

  • design-guide 프로젝트에 정의된 최신 헤더 디자인 스펙을 aim-frontend에 이식하여 일관된 사용자 경험을 제공하고자 함.
  • FSD 아키텍처의 shared 레이어 원칙에 따라 비즈니스 로직을 배제하고 순수 UI와 제어 가능한 Props 구조로 설계함.

✔ Checklist

  • 코드는 로컬에서 정상적으로 빌드됩니다 (pnpm build)
  • ESLint / Prettier 통과 (pnpm lint)
  • 네이밍/레이어 컨벤션 준수 (camelCase/PascalCase, is·has 불린 접두사, alias 계층 규칙)
  • 관련 문서/주석 반영 (필요 시)
  • 주요 로직에 테스트 또는 검증 완료 (Storybook 목업 확인)

🙏 Request

  • CONTRIBUT링.md에 정의된 스타일 클래스 패턴(baseClasses, variantClasses 분리 등)이 의도대로 리팩터링되었는지 중점적으로
    봐주시면 감사하겠습니다.

Summary by CodeRabbit

  • New Features

    • Added a reusable Navigation component with user profile dropdown, admin-mode toggle, auth actions, and logout.
    • Added a LogOut icon to the icon set.
  • Tests

    • Added Storybook stories demonstrating Navigation across auth and admin states.
  • Removals

    • Removed the legacy Header component and its Storybook stories.
  • Chores

    • Updated ignore rules to ignore GEMINI.md and preserved /test-results entry formatting.

@kimsman06 kimsman06 linked an issue Mar 12, 2026 that may be closed by this pull request
5 tasks
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e68d75f5-a194-48d9-aed7-f1d77e6ba4af

📥 Commits

Reviewing files that changed from the base of the PR and between f47c2a8 and 60d5687.

📒 Files selected for processing (1)
  • .gitignore

📝 Walkthrough

Walkthrough

Adds a new Navigation component with types, Storybook stories, and UI-barrel exports; introduces a LogOutIcon (duplicated in icons file); removes the Header component, its stories, and header exports; and updates .gitignore to add GEMINI.md and (re)include /test-results with minor formatting.

Changes

Cohort / File(s) Summary
Configuration
\.gitignore
Add GEMINI.md to ignore list and reintroduce /test-results entry (minor formatting change).
Icons
src/shared/ui/icons/index.tsx
Add LogOutIcon export — the same icon appears duplicated inside the file and should be deduplicated.
Navigation component
src/shared/ui/navigation/navigation.tsx
Add Navigation component plus NavItem, NavUser, and NavigationProps; includes sticky header, nav items, admin-mode toggle, profile dropdown, auth actions, and outside-click handling.
Navigation stories & barrel export
src/shared/ui/navigation/navigation.stories.tsx, src/shared/ui/index.ts
Add Storybook stories for multiple user/admin states; export Navigation, NavigationProps, NavItem, and NavUser from UI barrel.
Header removal
src/widgets/header/ui/header.tsx, src/widgets/header/ui/header.stories.tsx, src/widgets/header/index.ts
Remove Header component, its props/types, associated stories, and remove header exports from the header barrel.

Sequence Diagram

sequenceDiagram
    participant Browser as User/Browser
    participant Nav as Navigation Component
    participant Profile as Profile Dropdown
    participant Auth as Auth Handler

    Browser->>Nav: Render with props (items, user?, isAdminMode?)
    alt no user
        Nav->>Browser: Render Login / Signup buttons
    else user present
        Nav->>Browser: Render Profile button (+ Admin toggle if user.isAdmin)
    end

    Browser->>Nav: Click Profile button
    Nav->>Profile: toggle showProfile
    Profile->>Browser: show dropdown with name, email, type, actions

    alt user clicks Admin toggle
        Nav->>Auth: onAdminToggle()
        Auth-->>Nav: isAdminMode updated
        Nav->>Browser: update toggle label / UI
    end

    Browser->>Profile: Click Logout
    Profile->>Auth: onLogout()
    Auth-->>Browser: perform logout / redirect
    Nav->>Nav: update/render guest UI
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • jaeu5325
  • 1-J-1

Poem

🐰 I hopped in to add a nav so spry,
Toggles, profiles, icons nearby,
Header waved goodbye, stories bloom,
Log out, sign in — the UI's room,
Hop on, click through — the rabbit's high five!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: implementing a Navigation component. It is specific, concise, and directly reflects the primary objective of the pull request.
Description check ✅ Passed The description follows the template structure with all major sections completed: What is this PR?, Changes, Screenshots, Background/Context, and Checklist. Required information about the Navigation component implementation is well-documented.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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 feat/navigation-bar
📝 Coding Plan
  • Generate coding plan for human review comments

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

❤️ Share

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

Tip

CodeRabbit can approve the review once all CodeRabbit's comments are resolved.

Enable the reviews.request_changes_workflow setting to automatically approve the review once all CodeRabbit's comments are resolved.

@kimsman06 kimsman06 changed the title [Feat] #17 - 디자인 가이드 기반 공통 Navigation 컴포넌트 구현 [Feat] #17 - Navigation 컴포넌트 구현 Mar 12, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
src/shared/ui/navigation/navigation.tsx (2)

217-222: "내 포트폴리오" button lacks a callback prop.

This button only closes the dropdown without triggering any action. Consider adding an onPortfolioClick prop similar to onProfileClick for consistency and to allow parent components to handle navigation.

💡 Proposed fix

Add to NavigationProps:

onPortfolioClick?: () => void;

Then update the button:

                      <button
-                       onClick={() => setShowProfile(false)}
+                       onClick={() => {
+                         onPortfolioClick?.();
+                         setShowProfile(false);
+                       }}
                        className="text-left px-3 py-2.5 text-[14px] text-[var(--color-gray-900,`#1a1a1a`)] hover:bg-[var(--color-gray-100)] rounded-md transition-colors"
                      >
                        내 포트폴리오
                      </button>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/shared/ui/navigation/navigation.tsx` around lines 217 - 222, Add an
optional onPortfolioClick prop to NavigationProps and wire it into the portfolio
button so the parent can react when "내 포트폴리오" is clicked: update the
NavigationProps interface to include onPortfolioClick?: () => void; then modify
the button's onClick handler (currently using setShowProfile(false)) to call
onPortfolioClick if provided and still close the dropdown (call
setShowProfile(false) after or before invoking the prop); mirror how
onProfileClick is used to ensure consistent behavior and typing.

152-158: Consider adding role="switch" and aria-checked for better accessibility.

The toggle button has aria-label but lacks semantic switch attributes that screen readers use to announce toggle state.

♿ Proposed accessibility improvement
               <button
                 onClick={onAdminToggle}
                 className={getToggleClasses(isAdminMode)}
+                role="switch"
+                aria-checked={isAdminMode}
                 aria-label="관리자 모드 토글"
               >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/shared/ui/navigation/navigation.tsx` around lines 152 - 158, The toggle
button currently uses aria-label but is missing semantic switch attributes;
update the button element used with onAdminToggle (the one using
getToggleClasses/getToggleHandleClasses and isAdminMode) to include
role="switch" and aria-checked set from isAdminMode (e.g.,
aria-checked={isAdminMode}) so screen readers announce its state correctly while
keeping the existing onClick, className, and aria-label intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/shared/ui/navigation/navigation.tsx`:
- Around line 217-222: Add an optional onPortfolioClick prop to NavigationProps
and wire it into the portfolio button so the parent can react when "내 포트폴리오" is
clicked: update the NavigationProps interface to include onPortfolioClick?: ()
=> void; then modify the button's onClick handler (currently using
setShowProfile(false)) to call onPortfolioClick if provided and still close the
dropdown (call setShowProfile(false) after or before invoking the prop); mirror
how onProfileClick is used to ensure consistent behavior and typing.
- Around line 152-158: The toggle button currently uses aria-label but is
missing semantic switch attributes; update the button element used with
onAdminToggle (the one using getToggleClasses/getToggleHandleClasses and
isAdminMode) to include role="switch" and aria-checked set from isAdminMode
(e.g., aria-checked={isAdminMode}) so screen readers announce its state
correctly while keeping the existing onClick, className, and aria-label intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 568f039d-e6fa-47ae-89ce-e86e2ea809b6

📥 Commits

Reviewing files that changed from the base of the PR and between a751262 and 10b46f3.

⛔ Files ignored due to path filters (1)
  • public/assets/ajou-logo.svg is excluded by !**/*.svg
📒 Files selected for processing (5)
  • .gitignore
  • src/shared/ui/icons/index.tsx
  • src/shared/ui/index.ts
  • src/shared/ui/navigation/navigation.stories.tsx
  • src/shared/ui/navigation/navigation.tsx

@sebeeeen sebeeeen self-requested a review March 18, 2026 08:03
Copy link
Copy Markdown
Member

@sebeeeen sebeeeen left a comment

Choose a reason for hiding this comment

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

수고하셨습니다~!

@kimsman06 kimsman06 merged commit f8c78ee into dev Mar 18, 2026
1 check passed
@sebeeeen sebeeeen deleted the feat/navigation-bar branch March 23, 2026 08:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] Navigation 컴포넌트 구현

2 participants