From 1d2c28a3709921efd0edccc0882ea0c3400feae8 Mon Sep 17 00:00:00 2001 From: wagonsoftware Date: Mon, 31 Oct 2022 23:00:55 +0300 Subject: [PATCH] popup component added --- .../ui/src/lib/button/button.component.html | 2 +- .../ui/src/lib/button/button.component.scss | 26 +++- .../ui/src/lib/button/button.component.ts | 13 +- projects/ui/src/lib/game/game.component.html | 4 +- .../ui/src/lib/popup/popup.component.html | 21 +++ .../ui/src/lib/popup/popup.component.scss | 121 ++++++++++++++++++ .../ui/src/lib/popup/popup.component.spec.ts | 23 ++++ projects/ui/src/lib/popup/popup.component.ts | 55 ++++++++ .../ui/src/lib/popup/popup.directive.spec.ts | 8 ++ projects/ui/src/lib/popup/popup.directive.ts | 8 ++ projects/ui/src/lib/popup/popup.module.ts | 13 ++ .../ui/src/lib/popup/popup.service.spec.ts | 16 +++ projects/ui/src/lib/popup/popup.service.ts | 49 +++++++ projects/ui/src/lib/tag/tag.component.scss | 2 +- projects/ui/src/lib/ui.module.ts | 6 +- projects/ui/src/public-api.ts | 1 + .../main/main-menu/main-menu.component.html | 2 +- .../main/main-root/main-root.component.scss | 1 + src/app/components/main/main.module.ts | 2 + .../game-page/game-page.component.html | 12 +- .../sections/game-page/game-page.component.ts | 22 +++- .../components/sandbox/sandbox.component.html | 9 ++ .../components/sandbox/sandbox.component.scss | 5 + .../components/sandbox/sandbox.component.ts | 19 ++- src/styles.scss | 5 +- 25 files changed, 419 insertions(+), 26 deletions(-) create mode 100644 projects/ui/src/lib/popup/popup.component.html create mode 100644 projects/ui/src/lib/popup/popup.component.scss create mode 100644 projects/ui/src/lib/popup/popup.component.spec.ts create mode 100644 projects/ui/src/lib/popup/popup.component.ts create mode 100644 projects/ui/src/lib/popup/popup.directive.spec.ts create mode 100644 projects/ui/src/lib/popup/popup.directive.ts create mode 100644 projects/ui/src/lib/popup/popup.module.ts create mode 100644 projects/ui/src/lib/popup/popup.service.spec.ts create mode 100644 projects/ui/src/lib/popup/popup.service.ts diff --git a/projects/ui/src/lib/button/button.component.html b/projects/ui/src/lib/button/button.component.html index dddf583..e970e42 100644 --- a/projects/ui/src/lib/button/button.component.html +++ b/projects/ui/src/lib/button/button.component.html @@ -1,3 +1,3 @@ - diff --git a/projects/ui/src/lib/button/button.component.scss b/projects/ui/src/lib/button/button.component.scss index bb2563b..222f06b 100644 --- a/projects/ui/src/lib/button/button.component.scss +++ b/projects/ui/src/lib/button/button.component.scss @@ -6,14 +6,34 @@ display: flex; align-items: center; gap: var(--sk-gap-m); - background-color: var(--sk-accent); - border: none; border-radius: var(--sk-br-m); + border: none; cursor: pointer; - color: #fff; + font-weight: 500; &:hover { opacity: 0.9; } + + &[data-appearance="default"], &[data-appearance="primary"] { + background-color: var(--sk-primary); + color: #fff; + } + + &[data-appearance="secondary"] { + background-color: var(--sk-secondary); + color: #fff; + } + + &[data-appearance="outline"] { + color: #fff; + background-color: transparent; + box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.1); + } + + &[data-appearance="flat"] { + color: #fff; + background-color: transparent; + } } } diff --git a/projects/ui/src/lib/button/button.component.ts b/projects/ui/src/lib/button/button.component.ts index 4570358..46a7e6e 100644 --- a/projects/ui/src/lib/button/button.component.ts +++ b/projects/ui/src/lib/button/button.component.ts @@ -1,15 +1,12 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; @Component({ selector: 'skirda-button', templateUrl: './button.component.html', - styleUrls: ['./button.component.scss'] + styleUrls: ['./button.component.scss'], }) -export class ButtonComponent implements OnInit { - - constructor() { } - - ngOnInit(): void { - } +export class ButtonComponent { + @Input() appearance: string = 'default'; + constructor() {} } diff --git a/projects/ui/src/lib/game/game.component.html b/projects/ui/src/lib/game/game.component.html index 74fe23a..be8c381 100644 --- a/projects/ui/src/lib/game/game.component.html +++ b/projects/ui/src/lib/game/game.component.html @@ -6,5 +6,5 @@ description - - \ No newline at end of file + + diff --git a/projects/ui/src/lib/popup/popup.component.html b/projects/ui/src/lib/popup/popup.component.html new file mode 100644 index 0000000..8399381 --- /dev/null +++ b/projects/ui/src/lib/popup/popup.component.html @@ -0,0 +1,21 @@ + diff --git a/projects/ui/src/lib/popup/popup.component.scss b/projects/ui/src/lib/popup/popup.component.scss new file mode 100644 index 0000000..d146e57 --- /dev/null +++ b/projects/ui/src/lib/popup/popup.component.scss @@ -0,0 +1,121 @@ +:host { + position: absolute; + + @keyframes show { + from { + translate: 0px 20px; + opacity: 0; + } + to { + translate: 0px 0px; + opacity: 1; + } + } + + @keyframes hide { + from { + translate: 0px 0px; + opacity: 1; + } + to { + translate: 0px 20px; + opacity: 0; + } + } + + @keyframes showOverlay { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + + @keyframes hideOverlay { + from { + opacity: 1; + } + to { + opacity: 0; + } + } + + .popup-overlay { + display: block; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100vh; + background-color: rgba(0,0,0,0.5); + display: flex; + justify-content: center; + align-items: center; + opacity: 0; + + &.shown { + animation: showOverlay 0.2s ease 0s 1 forwards; + + .popup-window-wrapper { + animation: show 0.3s ease 0.1s 1 forwards; + } + } + &.hiding { + animation: hideOverlay 0.3s ease 0s 1 forwards; + + .popup-window-wrapper { + animation: hide 0.3s ease 0s 1 forwards; + } + } + + .popup-window-wrapper { + width: 500px; + background: linear-gradient(45deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.25)); + padding: 1px; + border-radius: 8px; + overflow: hidden; + translate: 0px 20px; + opacity: 0; + + .popup-window { + border-radius: 7px; + background-color: #222; + + .popup-head { + padding: 1rem; + display: flex; + align-items: center; + justify-content: space-between; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + + .head-title { + font-size: 1rem; + color: #aaa; + } + + .head-close { + width: 1.125rem; + height: 1.125rem; + cursor: pointer; + } + } + + .popup-body { + padding: 2rem; + text-align: center; + line-height: 140%; + } + + .popup-actions { + border-top: 1px solid rgba(255, 255, 255, 0.1); + display: flex; + align-items: center; + padding: 1rem; + gap: 0.25rem; + justify-content: flex-end; + } + } + } + } +} diff --git a/projects/ui/src/lib/popup/popup.component.spec.ts b/projects/ui/src/lib/popup/popup.component.spec.ts new file mode 100644 index 0000000..e561686 --- /dev/null +++ b/projects/ui/src/lib/popup/popup.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PopupComponent } from './popup.component'; + +describe('PopupComponent', () => { + let component: PopupComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ PopupComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(PopupComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/ui/src/lib/popup/popup.component.ts b/projects/ui/src/lib/popup/popup.component.ts new file mode 100644 index 0000000..1083c61 --- /dev/null +++ b/projects/ui/src/lib/popup/popup.component.ts @@ -0,0 +1,55 @@ +import { + AfterViewInit, + Component, + EventEmitter, + OnInit, + Output, + TemplateRef, + ViewChild, + ViewContainerRef, +} from '@angular/core'; +import { PopupDirective } from './popup.directive'; + +@Component({ + selector: 'skirda-popup', + templateUrl: './popup.component.html', + styleUrls: ['./popup.component.scss'], +}) +export class PopupComponent implements OnInit, AfterViewInit { + loaded: boolean = false; + hiding: boolean = false; + contentQueue?: TemplateRef; + + @Output() cancel: EventEmitter = new EventEmitter(); + @Output() confirm: EventEmitter = new EventEmitter(); + + @ViewChild(PopupDirective) private popupContent!: PopupDirective; + + constructor(private viewContainerRef: ViewContainerRef) {} + + ngOnInit(): void {} + + ngAfterViewInit(): void { + if (this.contentQueue) { + this.load(this.contentQueue); + this.contentQueue = undefined; + } + } + + load(template?: TemplateRef) { + this.loaded = true; + + if (!template) return; + if (!this.popupContent) { + this.contentQueue = template; + return; + } + + this.popupContent.viewContainerRef.createEmbeddedView(template); + } + + hide() { + this.loaded = false; + this.hiding = true; + } +} diff --git a/projects/ui/src/lib/popup/popup.directive.spec.ts b/projects/ui/src/lib/popup/popup.directive.spec.ts new file mode 100644 index 0000000..009a9d7 --- /dev/null +++ b/projects/ui/src/lib/popup/popup.directive.spec.ts @@ -0,0 +1,8 @@ +import { PopupDirective } from './popup.directive'; + +describe('PopupDirective', () => { + it('should create an instance', () => { + const directive = new PopupDirective(); + expect(directive).toBeTruthy(); + }); +}); diff --git a/projects/ui/src/lib/popup/popup.directive.ts b/projects/ui/src/lib/popup/popup.directive.ts new file mode 100644 index 0000000..477180d --- /dev/null +++ b/projects/ui/src/lib/popup/popup.directive.ts @@ -0,0 +1,8 @@ +import { Directive, ViewContainerRef } from '@angular/core'; + +@Directive({ + selector: '[skirdaPopup]', +}) +export class PopupDirective { + constructor(public viewContainerRef: ViewContainerRef) {} +} diff --git a/projects/ui/src/lib/popup/popup.module.ts b/projects/ui/src/lib/popup/popup.module.ts new file mode 100644 index 0000000..0efa7fa --- /dev/null +++ b/projects/ui/src/lib/popup/popup.module.ts @@ -0,0 +1,13 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { PopupComponent } from './popup.component'; +import { PopupDirective } from './popup.directive'; +import { ButtonModule } from '../button/button.module'; +import { IconModule } from '../icon/icon.module'; + +@NgModule({ + declarations: [PopupComponent, PopupDirective], + imports: [CommonModule, ButtonModule, IconModule], + exports: [PopupComponent, PopupDirective], +}) +export class PopupModule {} diff --git a/projects/ui/src/lib/popup/popup.service.spec.ts b/projects/ui/src/lib/popup/popup.service.spec.ts new file mode 100644 index 0000000..7e44414 --- /dev/null +++ b/projects/ui/src/lib/popup/popup.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { PopupService } from './popup.service'; + +describe('PopupService', () => { + let service: PopupService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(PopupService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/projects/ui/src/lib/popup/popup.service.ts b/projects/ui/src/lib/popup/popup.service.ts new file mode 100644 index 0000000..3c0a702 --- /dev/null +++ b/projects/ui/src/lib/popup/popup.service.ts @@ -0,0 +1,49 @@ +import { + ComponentRef, + EventEmitter, + Injectable, + Output, + TemplateRef, + ViewChild, +} from '@angular/core'; +import { first } from 'rxjs'; +import { PopupComponent } from './popup.component'; +import { PopupDirective } from './popup.directive'; + +@Injectable({ + providedIn: 'root', +}) +export class PopupService { + instance?: PopupComponent; + + constructor() {} + + open(portal: PopupDirective, template?: TemplateRef) { + let container = portal.viewContainerRef; + + container.clear(); + let componentRef = container.createComponent(PopupComponent); + + this.instance = componentRef.instance; + + this.instance.confirm.pipe(first()).subscribe(() => { + this.hide(componentRef); + }); + this.instance.cancel.pipe(first()).subscribe(() => { + this.hide(componentRef); + }); + + this.instance.load(template); + return this.instance; + } + + hide(componentRef: ComponentRef) { + if (!this.instance) return; + + this.instance.hide(); + + setTimeout(() => { + componentRef.destroy(); + }, 300); + } +} diff --git a/projects/ui/src/lib/tag/tag.component.scss b/projects/ui/src/lib/tag/tag.component.scss index d160a58..2595639 100644 --- a/projects/ui/src/lib/tag/tag.component.scss +++ b/projects/ui/src/lib/tag/tag.component.scss @@ -1,7 +1,7 @@ :host { &.filled .sk-tag { - background-color: var(--sk-accent); + background-color: var(--sk-primary); } .sk-tag { diff --git a/projects/ui/src/lib/ui.module.ts b/projects/ui/src/lib/ui.module.ts index f39f338..68312e3 100644 --- a/projects/ui/src/lib/ui.module.ts +++ b/projects/ui/src/lib/ui.module.ts @@ -10,6 +10,7 @@ import { ButtonModule } from './button/button.module'; import { TagModule } from './tag/tag.module'; import { PipesModule } from './pipes/pipes.module'; import { GameModule } from './game/game.module'; +import { PopupModule } from '../public-api'; @NgModule({ declarations: [], @@ -25,6 +26,7 @@ import { GameModule } from './game/game.module'; TagModule, PipesModule, GameModule, + PopupModule, ], exports: [ IconModule, @@ -34,9 +36,11 @@ import { GameModule } from './game/game.module'; TypographyModule, SectionLabelModule, ImageIconModule, + ButtonModule, TagModule, PipesModule, - GameModule + GameModule, + PopupModule, ], }) export class UiModule {} diff --git a/projects/ui/src/public-api.ts b/projects/ui/src/public-api.ts index 9b7aad3..94165b8 100644 --- a/projects/ui/src/public-api.ts +++ b/projects/ui/src/public-api.ts @@ -13,3 +13,4 @@ export * from './lib/image-icon/image-icon.module'; export * from './lib/tag/tag.module'; export * from './lib/pipes/pipes.module'; export * from './lib/game/game.module'; +export * from './lib/popup/popup.module'; diff --git a/src/app/components/main/main-menu/main-menu.component.html b/src/app/components/main/main-menu/main-menu.component.html index f014069..9e4671d 100644 --- a/src/app/components/main/main-menu/main-menu.component.html +++ b/src/app/components/main/main-menu/main-menu.component.html @@ -4,7 +4,7 @@
diff --git a/src/app/components/main/main-root/main-root.component.scss b/src/app/components/main/main-root/main-root.component.scss index 9758a66..aab26e6 100644 --- a/src/app/components/main/main-root/main-root.component.scss +++ b/src/app/components/main/main-root/main-root.component.scss @@ -18,6 +18,7 @@ width: 100vw; height: 100vh; background-size: cover; + position: inherit; } .content { diff --git a/src/app/components/main/main.module.ts b/src/app/components/main/main.module.ts index 035aec9..204bba5 100644 --- a/src/app/components/main/main.module.ts +++ b/src/app/components/main/main.module.ts @@ -16,6 +16,7 @@ import { ButtonModule } from 'projects/ui/src/lib/button/button.module'; import { TypographyModule } from 'projects/ui/src/lib/typography/typography.module'; import { IconModule } from 'projects/ui/src/lib/icon/icon.module'; import { DownloadsPageComponent } from './sections/downloads-page/downloads-page.component'; +import { PopupModule } from 'projects/ui/src/public-api'; @NgModule({ declarations: [ @@ -39,6 +40,7 @@ import { DownloadsPageComponent } from './sections/downloads-page/downloads-page TypographyModule, ButtonModule, IconModule, + PopupModule, ], exports: [ MainRootComponent, diff --git a/src/app/components/main/sections/game-page/game-page.component.html b/src/app/components/main/sections/game-page/game-page.component.html index 465e354..19797f2 100644 --- a/src/app/components/main/sections/game-page/game-page.component.html +++ b/src/app/components/main/sections/game-page/game-page.component.html @@ -1,3 +1,9 @@ + + +

πŸ˜³πŸ•ΆπŸ€

+

Church-key listicle whatever hoodie hexagon pour-over ascot paleo tacos, organic aesthetic tbh meggings raclette.

+
+
@@ -6,9 +12,13 @@
Game page will be here
+ Run game
-
\ No newline at end of file +
diff --git a/src/app/components/main/sections/game-page/game-page.component.ts b/src/app/components/main/sections/game-page/game-page.component.ts index 3297b81..eaa8a55 100644 --- a/src/app/components/main/sections/game-page/game-page.component.ts +++ b/src/app/components/main/sections/game-page/game-page.component.ts @@ -1,15 +1,29 @@ +import { TemplateRef, ViewChild } from '@angular/core'; import { Component, OnInit } from '@angular/core'; +import { PopupDirective } from 'projects/ui/src/lib/popup/popup.directive'; +import { PopupService } from 'projects/ui/src/lib/popup/popup.service'; +import { first } from 'rxjs'; @Component({ selector: 'app-game-page', templateUrl: './game-page.component.html', - styleUrls: ['./game-page.component.scss'] + styleUrls: ['./game-page.component.scss'], }) export class GamePageComponent implements OnInit { + @ViewChild(PopupDirective, { static: true }) popupPortal!: PopupDirective; - constructor() { } + constructor(private popup: PopupService) {} - ngOnInit(): void { + ngOnInit(): void {} + + openPopup(template: TemplateRef) { + let dialog = this.popup.open(this.popupPortal, template); + + dialog.cancel.pipe(first()).subscribe(() => { + console.log('cancel clicked'); + }); + dialog.confirm.pipe(first()).subscribe(() => { + console.log('confirm clicked'); + }); } - } diff --git a/src/app/components/sandbox/sandbox.component.html b/src/app/components/sandbox/sandbox.component.html index 0c62b41..64b33d7 100644 --- a/src/app/components/sandbox/sandbox.component.html +++ b/src/app/components/sandbox/sandbox.component.html @@ -20,3 +20,12 @@
+ +

Dialog

+ + + +

Warning

+

Church-key listicle whatever hoodie hexagon pour-over ascot paleo tacos, organic aesthetic tbh meggings raclette.

+
+Call popup diff --git a/src/app/components/sandbox/sandbox.component.scss b/src/app/components/sandbox/sandbox.component.scss index d37f839..1d33f76 100644 --- a/src/app/components/sandbox/sandbox.component.scss +++ b/src/app/components/sandbox/sandbox.component.scss @@ -10,6 +10,11 @@ gap: 1rem; } + hr { + width: 100%; + border-color: rgba(255, 255, 255, 0.1); + } + form { display: flex; flex-direction: column; diff --git a/src/app/components/sandbox/sandbox.component.ts b/src/app/components/sandbox/sandbox.component.ts index c1d42ab..d7e9b4e 100644 --- a/src/app/components/sandbox/sandbox.component.ts +++ b/src/app/components/sandbox/sandbox.component.ts @@ -1,5 +1,8 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; +import { PopupDirective } from 'projects/ui/src/lib/popup/popup.directive'; +import { PopupService } from 'projects/ui/src/lib/popup/popup.service'; +import { first } from 'rxjs'; @Component({ selector: 'app-sandbox', @@ -13,12 +16,24 @@ export class SandboxComponent implements OnInit { name: new FormControl(''), age: new FormControl(0), }); + @ViewChild(PopupDirective, { static: true }) popupPortal!: PopupDirective; - constructor() {} + constructor(private popup: PopupService) {} ngOnInit(): void {} print() { console.log(this.form); } + + openPopup(template: TemplateRef) { + let dialog = this.popup.open(this.popupPortal, template); + + dialog.cancel.pipe(first()).subscribe(() => { + console.log('cancel clicked'); + }); + dialog.confirm.pipe(first()).subscribe(() => { + console.log('confirm clicked'); + }); + } } diff --git a/src/styles.scss b/src/styles.scss index ce9314d..da5ebd5 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -22,8 +22,9 @@ button, input, textarea { // colors --sk-input: rgba(18,18,18,0.5); --sk-input-focus: rgba(18,18,18,0.9); - --sk-accent: #67A69E; - --sk-accent-dark: #2A3B39; + --sk-primary: #24927a; + --sk-secondary: #1b557d; + --sk-primary-dark: #2A3B39; // border-radius --sk-br-s: 0.25rem;