Adjust Settings Popup Position

This commit is contained in:
copecone committed 2026-03-26 14:18:17 +09:00
1 parent 010771b22a
commit 898df6a318
9 files changed
+64 -19

No files matched your search

+2 -2
View File
@@ -2,7 +2,7 @@
<router-outlet />
<div id="global-popup-root" class="popup-outlet">
@for (popup of popupService.activePopups(); track popup) {
<ng-container *ngComponentOutlet="popup" />
@for (popup of popupService.activePopups(); track popup.component) {
<ng-container *ngComponentOutlet="popup.component; inputs: popup.inputs" />
}
</div>
+8 -2
View File
@@ -1,5 +1,11 @@
<div class="popup-backdrop" (click)="onClose()">
<div class="popup-container" (click)="$event.stopPropagation()">
<div class="popup-backdrop" [class.center]="isCenter" (click)="onClose()">
<div class="popup-container"
[class.custom-pos]="!isCenter"
[style.top]="customStyle.top"
[style.left]="customStyle.left"
[style.right]="customStyle.right"
[style.bottom]="customStyle.bottom"
(click)="$event.stopPropagation()">
<header class="popup-header">
<div class="header-left">
<ng-content select="[header-left]"></ng-content>
+11 -4
View File
@@ -6,10 +6,13 @@
position: fixed;
inset: 0;
background-color: transparent;
display: flex;
justify-content: center;
align-items: center;
z-index: 100; /* .popup-outlet 내부에서의 상대적 순서 */
z-index: 100;
&.center {
display: flex;
justify-content: center;
align-items: center;
}
}
.popup-container {
@@ -26,6 +29,10 @@
border: oklch(0 0 0 / 20%) 2px solid;
gap: 15px;
&.custom-pos {
position: absolute;
}
}
@keyframes popup-enter {
+23 -1
View File
@@ -1,4 +1,11 @@
import { Component, output } from '@angular/core';
import { Component, input, output } from '@angular/core';
export type PopupPosition = {
top?: string;
left?: string;
right?: string;
bottom?: string;
};
@Component({
selector: 'app-popup',
@@ -7,6 +14,12 @@ import { Component, output } from '@angular/core';
styleUrl: './popup.scss',
})
export class PopupComponent {
/**
* 팝업의 위치 (기본값은 'center')
* 'center' 또는 { top, left, right, bottom } 객체를 받습니다.
*/
position = input<PopupPosition | 'center'>('center');
/**
* 팝업 닫기 요청 (배경 클릭 또는 닫기 버튼)
*/
@@ -15,4 +28,13 @@ export class PopupComponent {
onClose() {
this.closeRequest.emit();
}
get isCenter() {
return this.position() === 'center';
}
get customStyle() {
const pos = this.position();
return pos === 'center' ? {} : pos;
}
}
+1 -1
View File
@@ -15,6 +15,6 @@ export class HeaderMenu {
onSettingsClick() {
console.log('HeaderMenu: Settings clicked');
this.popupService.open(SettingsPopup);
this.popupService.open(SettingsPopup, { position: { top: '82px', right: '18px' } });
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
<app-popup (closeRequest)="close()">
<app-popup (closeRequest)="close()" [position]="position()">
<div header-left class="profile-section">
<img ngSrc="/guest_profile.png" alt="profile" class="avatar" width="24" height="24">
<span>{{ userName }}</span>
+7 -2
View File
@@ -1,5 +1,5 @@
import { Component, inject } from '@angular/core';
import { PopupComponent } from '../../components/popup/popup';
import { Component, inject, input } from '@angular/core';
import { PopupComponent, PopupPosition } from '../../components/popup/popup';
import { Dropdown, DropdownOption } from '../../components/dropdown/dropdown';
import { Switch } from '../../components/switch/switch';
import { NgOptimizedImage } from '@angular/common';
@@ -15,6 +15,11 @@ import { PopupService } from '../../services/popup.service';
export class SettingsPopup {
private popupService = inject(PopupService);
/**
* 팝업의 위치 (기본값은 'center')
*/
position = input<PopupPosition | 'center'>('center');
languages: DropdownOption[] = [
{ label: 'English', value: 'EN' },
{ label: '한국어', value: 'KR' },
+10 -5
View File
@@ -1,5 +1,10 @@
import { Injectable, signal, Type } from '@angular/core';
export interface PopupInstance {
component: Type<any>;
inputs?: Record<string, any>;
}
@Injectable({
providedIn: 'root',
})
@@ -7,15 +12,15 @@ export class PopupService {
/**
* 현재 활성화된 팝업 컴포넌트들의 리스트 (Signal)
*/
activePopups = signal<Type<any>[]>([]);
activePopups = signal<PopupInstance[]>([]);
/**
* 팝업을 엽니다. 이미 열려있는 동일한 컴포넌트가 있다면 중복해서 열지 않습니다.
*/
open<T>(component: Type<T>) {
open<T>(component: Type<T>, inputs?: Record<string, any>) {
this.activePopups.update((popups) => {
if (popups.includes(component)) return popups;
return [...popups, component];
if (popups.some((p) => p.component === component)) return popups;
return [...popups, { component, inputs }];
});
}
@@ -23,7 +28,7 @@ export class PopupService {
* 특정 컴포넌트를 닫습니다.
*/
close(component: Type<any>) {
this.activePopups.update((popups) => popups.filter((p) => p !== component));
this.activePopups.update((popups) => popups.filter((p) => p.component !== component));
}
/**