From d075c81496c06c3fb8b0003083767c6b6f288cad Mon Sep 17 00:00:00 2001 From: Xiao Gui <xgui3783@gmail.com> Date: Tue, 6 Sep 2022 13:56:58 +0200 Subject: [PATCH] feat: sane plugin window placements --- src/widget/constants.ts | 8 ++- src/widget/widget.module.ts | 6 ++- .../widgetPortal/widgetPortal.component.ts | 52 +++++++++++++++++-- .../widgetPortal/widgetPortal.style.css | 36 +++++-------- .../widgetPortal/widgetPortal.template.html | 48 +++++++++++++++-- src/widget/widgetStateIcon.pipe.ts | 26 ++++++++++ 6 files changed, 142 insertions(+), 34 deletions(-) create mode 100644 src/widget/widgetStateIcon.pipe.ts diff --git a/src/widget/constants.ts b/src/widget/constants.ts index a779b079a..53cc6568a 100644 --- a/src/widget/constants.ts +++ b/src/widget/constants.ts @@ -22,4 +22,10 @@ export type TypeActionToWidget<T> = (type: EnumActionToWidget, obj: T, option: I export const WIDGET_PORTAL_TOKEN = new InjectionToken<Record<string, unknown>>("WIDGET_PORTAL_TOKEN") -export const RM_WIDGET = new InjectionToken('RM_WIDGET') \ No newline at end of file +export const RM_WIDGET = new InjectionToken('RM_WIDGET') + +export enum EnumWidgetState { + MINIMIZED, + NORMAL, + MAXIMIZED, +} diff --git a/src/widget/widget.module.ts b/src/widget/widget.module.ts index 138ed6648..62b9d65ba 100644 --- a/src/widget/widget.module.ts +++ b/src/widget/widget.module.ts @@ -2,17 +2,20 @@ import { NgModule } from "@angular/core"; import { CommonModule } from "@angular/common"; import { ComponentsModule } from "src/components"; import { WidgetCanvas } from "./widgetCanvas.directive"; -import { WidgetPortal } from "./widgetPortal/widgetPortal.component"; +import { WidgetPortal } from "./widgetPortal/widgetPortal.component" import { MatCardModule } from "@angular/material/card"; import { DragDropModule } from "@angular/cdk/drag-drop"; import { MatButtonModule } from "@angular/material/button"; import { PortalModule } from "@angular/cdk/portal"; +import { MatTooltipModule } from "@angular/material/tooltip"; +import { WidgetStateIconPipe } from "./widgetStateIcon.pipe"; @NgModule({ imports:[ MatCardModule, DragDropModule, MatButtonModule, + MatTooltipModule, PortalModule, CommonModule, ComponentsModule, @@ -20,6 +23,7 @@ import { PortalModule } from "@angular/cdk/portal"; declarations: [ WidgetCanvas, WidgetPortal, + WidgetStateIconPipe, ], providers: [], exports: [ diff --git a/src/widget/widgetPortal/widgetPortal.component.ts b/src/widget/widgetPortal/widgetPortal.component.ts index 5e5cc05fa..cf7f0ea9a 100644 --- a/src/widget/widgetPortal/widgetPortal.component.ts +++ b/src/widget/widgetPortal/widgetPortal.component.ts @@ -1,6 +1,26 @@ import { ComponentPortal } from "@angular/cdk/portal"; -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Optional } from "@angular/core"; -import { RM_WIDGET } from "../constants"; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostBinding, Inject, Optional } from "@angular/core"; +import { RM_WIDGET, EnumWidgetState } from "../constants"; + +type TWidgetCss = { + transform: string + width: string +} + +const widgetStateToTransform: Record<EnumWidgetState, TWidgetCss> = { + [EnumWidgetState.MINIMIZED]: { + transform: `translate(100vw, 5vh)`, + width: '24rem' + }, + [EnumWidgetState.NORMAL]: { + transform: `translate(calc(100vw - 24rem), 5vh)`, + width: '24rem' + }, + [EnumWidgetState.MAXIMIZED]: { + transform: `translate(5vw, 5vh)`, + width: '90vw' + }, +} @Component({ selector: 'sxplr-widget-portal', @@ -13,6 +33,8 @@ import { RM_WIDGET } from "../constants"; export class WidgetPortal<T>{ + EnumWidgetState = EnumWidgetState + portal: ComponentPortal<T> private _name: string @@ -24,10 +46,30 @@ export class WidgetPortal<T>{ this.cdr.markForCheck() } - defaultPosition = { - x: 200, - y: 200, + minimizeReturnState: EnumWidgetState.NORMAL | EnumWidgetState.MAXIMIZED + + private _state: EnumWidgetState = EnumWidgetState.NORMAL + get state() { + return this._state } + set state(val: EnumWidgetState) { + if (val === EnumWidgetState.MINIMIZED) { + this.minimizeReturnState = this._state !== EnumWidgetState.MINIMIZED + ? this._state + : EnumWidgetState.NORMAL + } + this._state = val + this.transform = widgetStateToTransform[this._state]?.transform || widgetStateToTransform[EnumWidgetState.NORMAL].transform + this.width = widgetStateToTransform[this._state]?.width || widgetStateToTransform[EnumWidgetState.NORMAL].width + + this.cdr.markForCheck() + } + + @HostBinding('style.transform') + transform = widgetStateToTransform[ EnumWidgetState.NORMAL ].transform + + @HostBinding('style.width') + width = widgetStateToTransform[ EnumWidgetState.NORMAL ].width constructor( private cdr: ChangeDetectorRef, diff --git a/src/widget/widgetPortal/widgetPortal.style.css b/src/widget/widgetPortal/widgetPortal.style.css index 12e9c8096..3b374eee2 100644 --- a/src/widget/widgetPortal/widgetPortal.style.css +++ b/src/widget/widgetPortal/widgetPortal.style.css @@ -2,15 +2,18 @@ { pointer-events: none; display: block; - max-width: 24rem; + + width: 24rem; + height: 90vh; + + transition: all 160ms cubic-bezier(0.35, 0, 0.25, 1); } mat-card { pointer-events: all; - max-width: 36vw; - height: 36rem; - max-height: 90vh; + width: 100%; + height: 100%; } mat-card-content @@ -24,7 +27,7 @@ mat-card-content .widget-portal-header { display: flex; - justify-content: space-between; + justify-content: flex-end; align-items: center; } @@ -33,24 +36,13 @@ mat-card-content flex-grow: 1; } -.hover-grab -{ - opacity: 0.5; - transition: opacity 200ms ease-in-out; - cursor: move; -} - -.hover-grab:hover -{ - opacity: 1.0; -} - -.widget-grab-handle -{ - margin-right:1rem; -} - .widget-name { flex-grow: 1; } + +.when-minimized-nub +{ + position: absolute; + transform: translate(-5rem, 5rem); +} \ No newline at end of file diff --git a/src/widget/widgetPortal/widgetPortal.template.html b/src/widget/widgetPortal/widgetPortal.template.html index 7aff890d9..5e4e495fa 100644 --- a/src/widget/widgetPortal/widgetPortal.template.html +++ b/src/widget/widgetPortal/widgetPortal.template.html @@ -1,13 +1,41 @@ -<mat-card cdkDrag [cdkDragFreeDragPosition]="defaultPosition"> +<div *ngIf="state === EnumWidgetState.MINIMIZED" + class="when-minimized-nub"> + + <button mat-mini-fab + [matTooltip]="name" + color="primary" + class="sxplr-pe-all" + (click)="state = minimizeReturnState"> + <i [class]="minimizeReturnState | widgetStateIcon"></i> + </button> +</div> + +<mat-card> <mat-card-content> - <div class="widget-portal-header" cdkDragHandle> - <span class="hover-grab widget-grab-handle"> - <i class="fas fa-grip-vertical"></i> - </span> + <div class="widget-portal-header"> <span *ngIf="name" class="widget-name"> {{ name }} </span> + + <!-- state changer --> + <ng-template [ngTemplateOutlet]="stateBtnTmpl" + [ngTemplateOutletContext]="{ + $implicit: EnumWidgetState.MINIMIZED + }"> + </ng-template> + + <ng-template [ngTemplateOutlet]="stateBtnTmpl" + [ngTemplateOutletContext]="{ + $implicit: EnumWidgetState.NORMAL + }"> + </ng-template> + + <ng-template [ngTemplateOutlet]="stateBtnTmpl" + [ngTemplateOutletContext]="{ + $implicit: EnumWidgetState.MAXIMIZED + }"> + </ng-template> <button mat-icon-button (click)="exit()"> <i class="fas fa-times"></i> @@ -20,3 +48,13 @@ </div> </mat-card-content> </mat-card> + +<!-- template for plugin state --> +<ng-template #stateBtnTmpl let-btnstate> + <button + *ngIf="state !== btnstate" + (click)="state = btnstate" + mat-icon-button> + <i [class]="btnstate | widgetStateIcon"></i> + </button> +</ng-template> diff --git a/src/widget/widgetStateIcon.pipe.ts b/src/widget/widgetStateIcon.pipe.ts new file mode 100644 index 000000000..b7af88175 --- /dev/null +++ b/src/widget/widgetStateIcon.pipe.ts @@ -0,0 +1,26 @@ +import { Pipe, PipeTransform } from "@angular/core"; +import { EnumWidgetState } from "./constants" + +@Pipe({ + name: 'widgetStateIcon', + pure: true +}) + +export class WidgetStateIconPipe implements PipeTransform{ + public transform(state: EnumWidgetState): string { + switch (state) { + case EnumWidgetState.MINIMIZED: { + return 'fas fa-window-minimize' + } + case EnumWidgetState.NORMAL: { + return 'fas fa-window-restore' + } + case EnumWidgetState.MAXIMIZED: { + return 'fas fa-window-maximize' + } + default: { + return 'fas fa-window-restore' + } + } + } +} -- GitLab