Add Navigation Menu Component
This commit is contained in:
1 parent
7363684b2f
commit
25a9bca291
7 files changed
+136
-3
No files matched your search
@@ -37,7 +37,7 @@ $default_animation_duration: 0.2s;
|
|||||||
animation: popup-enter var(--animation-duration) $animation_timing;
|
animation: popup-enter var(--animation-duration) $animation_timing;
|
||||||
|
|
||||||
outline: light-dark(oklch(0 0 0 / 20%), oklch(1 0 0 / 20%)) 2px solid;
|
outline: light-dark(oklch(0 0 0 / 20%), oklch(1 0 0 / 20%)) 2px solid;
|
||||||
gap: 16px;
|
gap: 12px;
|
||||||
|
|
||||||
&.variant-glass {
|
&.variant-glass {
|
||||||
background-color: light-dark(oklch(1 0 0 / 60%), oklch(0 0 0 / 60%));
|
background-color: light-dark(oklch(1 0 0 / 60%), oklch(0 0 0 / 60%));
|
||||||
|
|||||||
@@ -56,6 +56,7 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
&.nav-link {
|
&.nav-link {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
|||||||
@@ -2,17 +2,18 @@ import {
|
|||||||
afterNextRender,
|
afterNextRender,
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
Component,
|
Component,
|
||||||
|
effect,
|
||||||
ElementRef,
|
ElementRef,
|
||||||
inject,
|
inject,
|
||||||
NgZone,
|
NgZone,
|
||||||
OnDestroy,
|
OnDestroy,
|
||||||
OnInit,
|
|
||||||
signal,
|
signal,
|
||||||
viewChild,
|
viewChild,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
import { PopupService } from '../../services/popup.service';
|
import { PopupService } from '../../services/popup.service';
|
||||||
import { SettingsPopup } from '../settings/settings';
|
import { SettingsPopup } from '../settings/settings';
|
||||||
|
import { NavigationMenu } from './navigation-menu';
|
||||||
import { TranslationService } from '../../services/translation.service';
|
import { TranslationService } from '../../services/translation.service';
|
||||||
import { SettingsService } from '../../services/settings.service';
|
import { SettingsService } from '../../services/settings.service';
|
||||||
|
|
||||||
@@ -57,6 +58,12 @@ export class HeaderMenu implements OnDestroy {
|
|||||||
private element: ElementRef,
|
private element: ElementRef,
|
||||||
private ngZone: NgZone,
|
private ngZone: NgZone,
|
||||||
) {
|
) {
|
||||||
|
effect(() => {
|
||||||
|
if (this.expandStage() > 0) {
|
||||||
|
this.popupService.close(NavigationMenu);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
afterNextRender(() => {
|
afterNextRender(() => {
|
||||||
this.ngZone.runOutsideAngular(() => {
|
this.ngZone.runOutsideAngular(() => {
|
||||||
this.resizeObserver = new ResizeObserver((entries) => {
|
this.resizeObserver = new ResizeObserver((entries) => {
|
||||||
@@ -147,7 +154,9 @@ export class HeaderMenu implements OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onHamburgerClick(): void {
|
onHamburgerClick(): void {
|
||||||
|
this.popupService.open(NavigationMenu, {
|
||||||
|
position: { top: '84px', right: '20px' },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onSettingsClick() {
|
onSettingsClick() {
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<app-popup [position]="position()" (closeRequest)="close()">
|
||||||
|
<div header-left class="menu-header-title">
|
||||||
|
<span class="material-symbols-outlined">menu</span>
|
||||||
|
<span>{{ translation.menu.menu }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="menu-content">
|
||||||
|
<div class="menu-section">
|
||||||
|
<a class="menu-item nav-link" [routerLink]="['/levels']" (click)="close()">{{ translation.menu.levels }}</a>
|
||||||
|
<span class="menu-item dummy-link">{{ translation.menu.community }}</span>
|
||||||
|
<span class="menu-item dummy-link">{{ translation.menu.leaderboard }}</span>
|
||||||
|
<span class="menu-item dummy-link">{{ translation.menu.about }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="menu-divider" />
|
||||||
|
|
||||||
|
<div class="menu-section">
|
||||||
|
<a class="menu-item nav-link" [routerLink]="['/known-issues']" (click)="close()">{{ translation.menu.knownIssues }}</a>
|
||||||
|
<span class="menu-item dummy-link"><strong>{{ translation.menu.login }}</strong></span>
|
||||||
|
<span class="menu-item dummy-link">{{ translation.menu.signup }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</app-popup>
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<PopupPosition | 'center'>('center');
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.popupService.close(NavigationMenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
|
|
||||||
|
padding-top: 4px;
|
||||||
padding-bottom: 12px;
|
padding-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user