fix: Improve plugin ui entry points, Fix chat scroll, fix notifications, fix user rights
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
import {
|
||||
ElementRef,
|
||||
Injectable,
|
||||
inject
|
||||
} from '@angular/core';
|
||||
import {
|
||||
ConnectedPosition,
|
||||
Overlay,
|
||||
OverlayRef
|
||||
} from '@angular/cdk/overlay';
|
||||
import { ComponentPortal } from '@angular/cdk/portal';
|
||||
import {
|
||||
Subscription,
|
||||
filter,
|
||||
fromEvent
|
||||
} from 'rxjs';
|
||||
import { PluginActionMenuComponent } from './plugin-action-menu.component';
|
||||
|
||||
const GAP = 10;
|
||||
const VIEWPORT_MARGIN = 8;
|
||||
const POSITIONS: ConnectedPosition[] = [
|
||||
{ originX: 'end', originY: 'top', overlayX: 'start', overlayY: 'top', offsetX: GAP },
|
||||
{ originX: 'end', originY: 'bottom', overlayX: 'start', overlayY: 'bottom', offsetX: GAP },
|
||||
{ originX: 'start', originY: 'top', overlayX: 'end', overlayY: 'top', offsetX: -GAP },
|
||||
{ originX: 'start', originY: 'bottom', overlayX: 'end', overlayY: 'bottom', offsetX: -GAP }
|
||||
];
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class PluginActionMenuService {
|
||||
private readonly overlay = inject(Overlay);
|
||||
private currentOrigin: HTMLElement | null = null;
|
||||
private overlayRef: OverlayRef | null = null;
|
||||
private overlaySubscriptions: Subscription | null = null;
|
||||
private scrollBlocker: (() => void) | null = null;
|
||||
|
||||
open(origin: ElementRef | HTMLElement): void {
|
||||
const rawEl = origin instanceof ElementRef ? origin.nativeElement : origin;
|
||||
|
||||
if (this.overlayRef) {
|
||||
const sameOrigin = rawEl === this.currentOrigin;
|
||||
|
||||
this.close();
|
||||
|
||||
if (sameOrigin) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const elementRef = origin instanceof ElementRef ? origin : new ElementRef(origin);
|
||||
|
||||
this.currentOrigin = rawEl;
|
||||
|
||||
const positionStrategy = this.overlay
|
||||
.position()
|
||||
.flexibleConnectedTo(elementRef)
|
||||
.withPositions(POSITIONS)
|
||||
.withViewportMargin(VIEWPORT_MARGIN)
|
||||
.withPush(true);
|
||||
|
||||
this.overlayRef = this.overlay.create({
|
||||
positionStrategy,
|
||||
scrollStrategy: this.overlay.scrollStrategies.noop()
|
||||
});
|
||||
|
||||
this.syncThemeVars();
|
||||
|
||||
const componentRef = this.overlayRef.attach(new ComponentPortal(PluginActionMenuComponent));
|
||||
const subscriptions = new Subscription();
|
||||
|
||||
subscriptions.add(componentRef.instance.closed.subscribe(() => this.close()));
|
||||
subscriptions.add(fromEvent<PointerEvent>(document, 'pointerdown')
|
||||
.pipe(
|
||||
filter((event) => {
|
||||
const target = event.target as Node;
|
||||
|
||||
if (this.overlayRef?.overlayElement.contains(target)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.currentOrigin?.contains(target)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
)
|
||||
.subscribe(() => this.close()));
|
||||
|
||||
this.overlaySubscriptions = subscriptions;
|
||||
this.blockScroll();
|
||||
}
|
||||
|
||||
close(): void {
|
||||
this.scrollBlocker?.();
|
||||
this.scrollBlocker = null;
|
||||
this.overlaySubscriptions?.unsubscribe();
|
||||
this.overlaySubscriptions = null;
|
||||
|
||||
if (this.overlayRef) {
|
||||
this.overlayRef.dispose();
|
||||
this.overlayRef = null;
|
||||
this.currentOrigin = null;
|
||||
}
|
||||
}
|
||||
|
||||
private blockScroll(): void {
|
||||
const handler = (event: Event): void => {
|
||||
if (this.overlayRef?.overlayElement.contains(event.target as Node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
};
|
||||
const opts: AddEventListenerOptions = { passive: false, capture: true };
|
||||
|
||||
document.addEventListener('wheel', handler, opts);
|
||||
document.addEventListener('touchmove', handler, opts);
|
||||
|
||||
this.scrollBlocker = () => {
|
||||
document.removeEventListener('wheel', handler, opts);
|
||||
document.removeEventListener('touchmove', handler, opts);
|
||||
};
|
||||
}
|
||||
|
||||
private syncThemeVars(): void {
|
||||
const appRoot = document.querySelector<HTMLElement>('[data-theme-key="appRoot"]');
|
||||
const container = document.querySelector<HTMLElement>('.cdk-overlay-container');
|
||||
|
||||
if (!appRoot || !container) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const prop of Array.from(appRoot.style)) {
|
||||
if (prop.startsWith('--')) {
|
||||
container.style.setProperty(prop, appRoot.style.getPropertyValue(prop));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user