From 25a9bca291c0e7903308ab6df1810bcf31f63fca Mon Sep 17 00:00:00 2001 From: copecone Date: Tue, 5 May 2026 15:17:52 +0900 Subject: [PATCH] Add Navigation Menu Component --- src/app/components/popup/popup.scss | 2 +- src/app/features/header-menu/header-menu.scss | 1 + src/app/features/header-menu/header-menu.ts | 13 +++- .../features/header-menu/navigation-menu.html | 23 ++++++ .../features/header-menu/navigation-menu.scss | 73 +++++++++++++++++++ .../features/header-menu/navigation-menu.ts | 26 +++++++ src/app/features/settings/settings.scss | 1 + 7 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 src/app/features/header-menu/navigation-menu.html create mode 100644 src/app/features/header-menu/navigation-menu.scss create mode 100644 src/app/features/header-menu/navigation-menu.ts diff --git a/src/app/components/popup/popup.scss b/src/app/components/popup/popup.scss index aa2583e..b871800 100644 --- a/src/app/components/popup/popup.scss +++ b/src/app/components/popup/popup.scss @@ -37,7 +37,7 @@ $default_animation_duration: 0.2s; animation: popup-enter var(--animation-duration) $animation_timing; outline: light-dark(oklch(0 0 0 / 20%), oklch(1 0 0 / 20%)) 2px solid; - gap: 16px; + gap: 12px; &.variant-glass { background-color: light-dark(oklch(1 0 0 / 60%), oklch(0 0 0 / 60%)); diff --git a/src/app/features/header-menu/header-menu.scss b/src/app/features/header-menu/header-menu.scss index 7d71164..7abfe03 100644 --- a/src/app/features/header-menu/header-menu.scss +++ b/src/app/features/header-menu/header-menu.scss @@ -56,6 +56,7 @@ cursor: pointer; display: flex; align-items: center; + border-radius: 4px; &.nav-link { font-weight: 700; diff --git a/src/app/features/header-menu/header-menu.ts b/src/app/features/header-menu/header-menu.ts index 3e232e5..7e7e8d8 100644 --- a/src/app/features/header-menu/header-menu.ts +++ b/src/app/features/header-menu/header-menu.ts @@ -2,17 +2,18 @@ import { afterNextRender, ChangeDetectionStrategy, Component, + effect, ElementRef, inject, NgZone, OnDestroy, - OnInit, signal, viewChild, } from '@angular/core'; import { RouterLink } from '@angular/router'; import { PopupService } from '../../services/popup.service'; import { SettingsPopup } from '../settings/settings'; +import { NavigationMenu } from './navigation-menu'; import { TranslationService } from '../../services/translation.service'; import { SettingsService } from '../../services/settings.service'; @@ -57,6 +58,12 @@ export class HeaderMenu implements OnDestroy { private element: ElementRef, private ngZone: NgZone, ) { + effect(() => { + if (this.expandStage() > 0) { + this.popupService.close(NavigationMenu); + } + }); + afterNextRender(() => { this.ngZone.runOutsideAngular(() => { this.resizeObserver = new ResizeObserver((entries) => { @@ -147,7 +154,9 @@ export class HeaderMenu implements OnDestroy { } onHamburgerClick(): void { - + this.popupService.open(NavigationMenu, { + position: { top: '84px', right: '20px' }, + }); } onSettingsClick() { diff --git a/src/app/features/header-menu/navigation-menu.html b/src/app/features/header-menu/navigation-menu.html new file mode 100644 index 0000000..984d6ce --- /dev/null +++ b/src/app/features/header-menu/navigation-menu.html @@ -0,0 +1,23 @@ + + + + + diff --git a/src/app/features/header-menu/navigation-menu.scss b/src/app/features/header-menu/navigation-menu.scss new file mode 100644 index 0000000..19c022c --- /dev/null +++ b/src/app/features/header-menu/navigation-menu.scss @@ -0,0 +1,73 @@ +:host { + display: block; + user-select: none; +} + +.menu-header-title { + display: flex; + align-items: center; + gap: 12px; + font-size: 18px; + + .material-symbols-outlined { + font-size: 24px; + } +} + +.menu-content { + display: flex; + flex-direction: column; + min-width: 276px; + padding-bottom: 12px; + gap: 12px; +} + +.menu-section { + display: flex; + flex-direction: column; +} + +.menu-divider { + height: 1px; + border: none; + background-color: light-dark(oklch(0 0 0 / 20%), oklch(1 0 0 / 20%)); + margin: 0 6px; +} + +.menu-item { + display: flex; + align-items: center; + align-content: center; + height: 40px; + padding-left: 12px; + text-decoration: none; + color: inherit; + font-size: 18px; + cursor: pointer; + vertical-align: middle; + transition: background-color 0.2s; + border-radius: 4px; + + .material-symbols-outlined { + font-size: 24px; + color: light-dark(oklch(0.4 0 0), oklch(0.8 0 0)); + } + + strong { + font-weight: 700; + } + + &.nav-link { + font-weight: 700; + color: oklch(0.6 0.15 250); + transition: opacity 0.3s; + + &:hover { + opacity: 0.7; + } + } + + &.dummy-link { + cursor: not-allowed; + } +} diff --git a/src/app/features/header-menu/navigation-menu.ts b/src/app/features/header-menu/navigation-menu.ts new file mode 100644 index 0000000..85413e1 --- /dev/null +++ b/src/app/features/header-menu/navigation-menu.ts @@ -0,0 +1,26 @@ +import { Component, inject, input } from '@angular/core'; +import { RouterLink } from '@angular/router'; +import { PopupComponent, PopupPosition } from '../../components/popup/popup'; +import { PopupService } from '../../services/popup.service'; +import { TranslationService } from '../../services/translation.service'; + +@Component({ + selector: 'navigation-menu', + standalone: true, + imports: [PopupComponent, RouterLink], + templateUrl: './navigation-menu.html', + styleUrl: './navigation-menu.scss', +}) +export class NavigationMenu { + private popupService = inject(PopupService); + protected translation = inject(TranslationService).translation; + + /** + * 팝업의 위치 + */ + position = input('center'); + + close() { + this.popupService.close(NavigationMenu); + } +} diff --git a/src/app/features/settings/settings.scss b/src/app/features/settings/settings.scss index 01cac04..0cb1888 100644 --- a/src/app/features/settings/settings.scss +++ b/src/app/features/settings/settings.scss @@ -23,6 +23,7 @@ flex-direction: column; gap: 16px; + padding-top: 4px; padding-bottom: 12px; }