Adjust Settings Popup Position
This commit is contained in:
1 parent
010771b22a
commit
898df6a318
9 files changed
+64
-19
No files matched your search
@@ -1,7 +1,7 @@
|
||||
# AefComponentTest Docker 이미지 빌드 및 추출 스크립트
|
||||
|
||||
$IMAGE_NAME = "aef-component-test"
|
||||
$TAG = "0.0.2"
|
||||
$TAG = "0.0.3"
|
||||
$OUTPUT_FILE = "aef-component-test.tar"
|
||||
|
||||
Write-Host "--- Docker 이미지 빌드 시작: ${IMAGE_NAME}:${TAG} ---" -ForegroundColor Cyan
|
||||
|
||||
+2
-2
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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,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>
|
||||
|
||||
@@ -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' },
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user