new icons, advanced popup windows

This commit is contained in:
wagonsoftware 2022-11-01 23:25:26 +03:00
parent e7624ab550
commit 4ef0f5efba
38 changed files with 505 additions and 154 deletions

38
package-lock.json generated
View File

@ -17,6 +17,8 @@
"@angular/platform-browser": "^14.1.0",
"@angular/platform-browser-dynamic": "^14.1.0",
"@angular/router": "^14.1.0",
"@ng-icons/core": "^22.4.0",
"@ng-icons/tabler-icons": "^22.4.0",
"fast-average-color": "^9.1.1",
"moment": "^2.29.4",
"rxjs": "~7.5.0",
@ -2632,6 +2634,26 @@
"resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A=="
},
"node_modules/@ng-icons/core": {
"version": "22.4.0",
"resolved": "https://registry.npmjs.org/@ng-icons/core/-/core-22.4.0.tgz",
"integrity": "sha512-sOACYxjGuJ7TQEARD7XhLF0mZGTTkEF8o2yNl3J+KXTPz+A5CptkT/57S+UNdXXeKuw9c6xlYpxUWu3tISkp/Q==",
"dependencies": {
"tslib": "^2.2.0"
},
"peerDependencies": {
"@angular/common": ">=14.0.0",
"@angular/core": ">=14.0.0"
}
},
"node_modules/@ng-icons/tabler-icons": {
"version": "22.4.0",
"resolved": "https://registry.npmjs.org/@ng-icons/tabler-icons/-/tabler-icons-22.4.0.tgz",
"integrity": "sha512-aF9MLx//95Yp3smWNGRUaHtYecO37TtubukNArTdxShKX3+wThdPb5rvIeIq9KoOEq2iJn2iWXHq+XRdPILKrw==",
"dependencies": {
"tslib": "^2.2.0"
}
},
"node_modules/@ngtools/webpack": {
"version": "14.2.6",
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.6.tgz",
@ -13458,6 +13480,22 @@
"resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A=="
},
"@ng-icons/core": {
"version": "22.4.0",
"resolved": "https://registry.npmjs.org/@ng-icons/core/-/core-22.4.0.tgz",
"integrity": "sha512-sOACYxjGuJ7TQEARD7XhLF0mZGTTkEF8o2yNl3J+KXTPz+A5CptkT/57S+UNdXXeKuw9c6xlYpxUWu3tISkp/Q==",
"requires": {
"tslib": "^2.2.0"
}
},
"@ng-icons/tabler-icons": {
"version": "22.4.0",
"resolved": "https://registry.npmjs.org/@ng-icons/tabler-icons/-/tabler-icons-22.4.0.tgz",
"integrity": "sha512-aF9MLx//95Yp3smWNGRUaHtYecO37TtubukNArTdxShKX3+wThdPb5rvIeIq9KoOEq2iJn2iWXHq+XRdPILKrw==",
"requires": {
"tslib": "^2.2.0"
}
},
"@ngtools/webpack": {
"version": "14.2.6",
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.6.tgz",

View File

@ -19,6 +19,8 @@
"@angular/platform-browser": "^14.1.0",
"@angular/platform-browser-dynamic": "^14.1.0",
"@angular/router": "^14.1.0",
"@ng-icons/core": "^22.4.0",
"@ng-icons/tabler-icons": "^22.4.0",
"fast-average-color": "^9.1.1",
"moment": "^2.29.4",
"rxjs": "~7.5.0",

View File

@ -9,7 +9,10 @@
border-radius: var(--sk-br-m);
border: none;
cursor: pointer;
font-size: 1rem;
font-weight: 500;
outline: none;
appearance: none;
&:hover {
opacity: 0.9;

View File

@ -0,0 +1,6 @@
export type ButtonAppearance =
| 'default'
| 'primary'
| 'secondary'
| 'outline'
| 'flat';

View File

@ -0,0 +1,18 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { KeyboardDirective } from './keyboard.directive';
@NgModule({
declarations: [
KeyboardDirective
],
imports: [
CommonModule
],
exports: [
KeyboardDirective
]
})
export class DirectivesModule { }

View File

@ -0,0 +1,8 @@
import { KeyboardDirective } from './keyboard.directive';
describe('KeyboardDirective', () => {
it('should create an instance', () => {
const directive = new KeyboardDirective();
expect(directive).toBeTruthy();
});
});

View File

@ -0,0 +1,18 @@
import { Directive, EventEmitter, HostListener, Output } from '@angular/core';
@Directive({
selector: '[skirdaKeyboard]',
})
export class KeyboardDirective {
@Output() escape: EventEmitter<KeyboardEvent> = new EventEmitter();
constructor() {}
@HostListener('window:keydown.Escape', ['$event']) keyboardHandler(
event: KeyboardEvent
) {
event.preventDefault();
event.stopPropagation();
this.escape.emit(event);
}
}

View File

@ -6,5 +6,5 @@
</div>
<skirda-text>description</skirda-text>
</div>
<skirda-icon name="play" size="16" (click)="run(game)" color="var(--sk-primary)"></skirda-icon>
<skirda-icon name="play" size="24" (click)="run(game)" color="var(--sk-primary)"></skirda-icon>
</div>

View File

@ -1 +1 @@
<div class="icon" [attr.style]="'--local-size:' + sizeWithUnit + ';--local-color:' + color" [ngClass]="'skirda-' + name"></div>
<ng-icon [name]="iconName" [size]="sizeWithUnit" [color]="color"></ng-icon>

View File

@ -1,6 +1,4 @@
@import './skirda/skirda.css';
:host::ng-deep {
:host {
display: flex;
align-items: center;
justify-content: center;

View File

@ -1,5 +1,6 @@
import { Component, Input, OnInit } from '@angular/core';
import { environment } from 'src/environments/environment';
import { icons } from './icons';
const BASE_SIZE = 24;
const BASE_STROKE_WIDTH = 1.5;
@ -9,17 +10,17 @@ const BASE_STROKE_WIDTH = 1.5;
templateUrl: './icon.component.html',
styleUrls: ['./icon.component.scss'],
})
export class IconComponent implements OnInit {
export class IconComponent {
@Input() name!: string;
@Input() size: number | string = 24;
@Input() sizeUnit: string = 'px';
@Input() color: string = '#fff';
constructor() {}
ngOnInit(): void {}
get sizeWithUnit() {
return this.size + this.sizeUnit;
}
get iconName() {
return icons.get(this.name) ?? 'tablerIcons';
}
}

View File

@ -1,10 +1,34 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { IconComponent } from './icon.component';
import { NgIconsModule } from '@ng-icons/core';
import {
tablerIcons,
tablerSearch,
tablerLayoutSidebar,
tablerServerBolt,
tablerDeviceGamepad2,
tablerUsers,
tablerDownload,
tablerPlayerPlay,
tablerX,
} from '@ng-icons/tabler-icons';
const icons = {
tablerIcons,
tablerSearch,
tablerLayoutSidebar,
tablerServerBolt,
tablerDeviceGamepad2,
tablerUsers,
tablerDownload,
tablerPlayerPlay,
tablerX,
};
@NgModule({
declarations: [IconComponent],
imports: [CommonModule],
imports: [CommonModule, NgIconsModule.withIcons(icons)],
exports: [IconComponent],
})
export class IconModule {}

View File

@ -0,0 +1,12 @@
const icons: Map<string, string> = new Map();
icons.set('search', 'tablerSearch');
icons.set('menu-panel', 'tablerLayoutSidebar');
icons.set('server', 'tablerServerBolt');
icons.set('library', 'tablerDeviceGamepad2');
icons.set('friends', 'tablerUsers');
icons.set('download', 'tablerDownload');
icons.set('play', 'tablerPlayerPlay');
icons.set('close', 'tablerX');
export { icons };

View File

@ -1,42 +0,0 @@
@font-face {
font-family: 'skirda';
src: url('./skirda.eot?27107141');
src: url('./skirda.eot?27107141#iefix') format('embedded-opentype'),
url('./skirda.woff2?27107141') format('woff2'),
url('./skirda.woff?27107141') format('woff'),
url('./skirda.ttf?27107141') format('truetype'),
url('./skirda.svg?27107141#skirda') format('svg');
font-weight: normal;
font-style: normal;
}
/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: 'skirda';
src: url('./skirda.svg?27107141#skirda') format('svg');
}
}
[class^="skirda-"]:before, [class*=" skirda-"]:before {
font-family: "skirda";
display: inline-block;
text-decoration: inherit;
text-align: center;
font-variant: normal;
text-transform: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.skirda-discord:before { content: '\e800'; } /* '' */
.skirda-friends:before { content: '\e801'; } /* '' */
.skirda-menu-panel:before { content: '\e802'; } /* '' */
.skirda-play:before { content: '\e803'; } /* '' */
.skirda-search:before { content: '\e804'; } /* '' */
.skirda-server:before { content: '\e805'; } /* '' */
.skirda-sign-out:before { content: '\e806'; } /* '' */
.skirda-favorite:before { content: '\e807'; } /* '' */
.skirda-library:before { content: '\e808'; } /* '' */
.skirda-download:before { content: '\e809'; } /* '' */

View File

@ -1,30 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Copyright (C) 2022 by original authors @ fontello.com</metadata>
<defs>
<font id="skirda" horiz-adv-x="1000" >
<font-face font-family="skirda" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
<missing-glyph horiz-adv-x="1000" />
<glyph glyph-name="discord" unicode="&#xe800;" d="M577 767l-26-48-1-2c-33 2-67 2-100 0l-2 2-25 48-54-10c-67-12-131-33-191-62l-19-9-12-18c-118-185-151-368-135-546l3-33 26-20c80-61 157-99 234-124l52-17 32 46c13 17 24 36 35 56 70-14 142-15 212-1 10-19 22-38 35-56l32-45 52 17c77 25 154 63 234 124l26 20 3 33c19 207-33 388-136 546l-11 18-19 9c-60 29-124 50-191 62z m-194-84c7-13 16-32 22-47 63 10 126 10 190 0 6 15 15 34 22 47 61-10 118-29 172-55 95-146 141-310 124-500-72-55-142-89-211-111-2 3-5 7-7 11-5 7-10 14-14 22-9 14-17 29-24 44 6 2 11 4 17 7 14 6 29 13 42 21 2 1 3 2 4 3 3 1 6 3 8 4-6 5-12 10-17 15-21-10-42-19-63-26-26-9-51-15-77-19-47-7-95-7-142 1-26 4-51 10-77 18-21 7-42 16-63 26-5-5-11-10-17-15 3-1 5-3 8-5 1 0 3-1 4-2 14-8 28-15 43-22 5-2 11-4 16-6-7-15-15-30-24-44-4-7-9-15-14-22-2-4-5-8-7-11-69 22-139 56-211 111-15 164 15 329 123 499 54 27 112 46 173 56z m-21-278c-42 0-75-40-75-88 0-48 33-88 75-88 41 0 75 40 75 88 0 48-34 88-75 88z m277 0c-42 0-75-40-75-88 0-48 33-88 75-88 41 0 74 40 74 88 1 48-33 88-74 88z" horiz-adv-x="1000" />
<glyph glyph-name="friends" unicode="&#xe801;" d="M253 804c-80 0-145-65-145-145a38 38 0 0 1 0 0c0-78 62-142 139-145a38 38 0 0 1 6 1 38 38 0 0 1 5-1c77 3 140 67 140 145 0 80-66 145-145 145z m493 0c-79 0-145-65-145-145 0-78 63-142 140-145a38 38 0 0 1 5 1 38 38 0 0 1 5-1c78 3 140 67 140 145a38 38 0 0 1 0 0 38 38 0 0 1 0 0 38 38 0 0 1 0 0c0 80-65 145-145 145z m-493-75c39 0 70-30 70-70 0-38-29-67-65-70-4 1-7 1-10 0-37 3-65 32-65 70 0 39 30 70 70 70z m493 0c40 0 70-31 70-70 0-38-28-67-65-70-3 1-6 1-10 0-36 3-65 32-65 70 0 40 31 70 70 70z m-250-236c-79 0-145-65-145-145 0-78 63-142 140-145a38 38 0 0 1 5 0 38 38 0 0 1 5 0c78 2 140 67 140 145a38 38 0 0 1 0 0 38 38 0 0 1 0 0 38 38 0 0 1 0 0c0 79-65 145-145 145z m-247-1c-17 0-33-1-50-4-33-6-65-18-92-36-37-25-61-62-61-102 0-40 24-78 61-103 54-36 125-47 191-36a38 38 0 0 1 31 44 38 38 0 0 1-44 30c-48-8-103 2-137 25a38 38 0 0 1 0 0c-21 14-27 28-27 40 0 11 6 25 27 40 34 22 90 32 138 24a38 38 0 0 1 44 30 38 38 0 0 1-31 43c-16 3-33 5-50 5z m501 0c-17 0-34-2-51-5a38 38 0 0 1-30-43 38 38 0 0 1 43-30c49 8 104-2 139-24 21-15 27-29 27-40 0-12-6-26-28-40a38 38 0 0 1 0 0c-33-23-88-33-137-25a38 38 0 0 1-43-30 38 38 0 0 1 31-44c66-11 136 0 191 36 37 25 61 63 61 103 0 40-24 77-61 102a38 38 0 0 1 0 0c-27 18-59 30-92 36-17 3-34 4-50 4z m-254-74c40 0 70-31 70-70 0-38-29-68-65-70-3 0-6 0-10 0-36 3-65 32-65 70 0 39 31 70 70 70z m4-237c-50 0-101-13-142-41a38 38 0 0 1 0 0c-37-24-61-62-61-102 0-40 24-78 61-103 82-55 202-55 284 0 37 25 61 63 61 103 0 40-24 78-61 102-41 28-91 41-142 41z m0-78c38 0 75-8 101-25 21-14 27-28 27-40 0-12-6-26-27-40a38 38 0 0 1-1 0c-51-34-149-34-200 0a38 38 0 0 1 0 0c-22 14-28 28-28 40 0 12 6 26 28 40 25 17 63 25 100 25z" horiz-adv-x="1000" />
<glyph glyph-name="menu-panel" unicode="&#xe802;" d="M375 804c-109 0-194-22-250-78-57-57-79-142-79-251v-250c0-109 22-194 79-251 56-56 141-78 250-78h250c109 0 194 22 251 78 56 57 78 142 78 251v250c0 109-22 194-78 251-57 56-142 78-251 78z m0-75h213v-758h-213c-99 0-160 19-197 57-37 37-57 98-57 197v250c0 99 20 160 57 198 37 37 98 56 197 56z m288-1c77-4 127-23 160-55 37-38 56-99 56-198v-250c0-99-19-160-56-197-33-33-83-52-160-56z" horiz-adv-x="1000" />
<glyph glyph-name="play" unicode="&#xe803;" d="M240 845c-101-2-194-84-194-196v-598c0-149 165-245 294-170v0l258 149 258 150c129 75 129 265 0 340l-258 150a38 38 0 0 1 0 0l-258 149c-32 19-67 27-100 26z m0-74c20 1 42-5 63-17l258-149 258-150a38 38 0 0 1 0 0c82-47 82-163 0-210a38 38 0 0 1 0 0l-258-150-258-149c-82-48-182 10-182 105v598c0 72 56 122 119 122z" horiz-adv-x="1000" />
<glyph glyph-name="search" unicode="&#xe804;" d="M438 804c-216 0-392-176-392-391 0-216 176-392 392-392 215 0 391 176 391 392 0 215-176 391-391 391z m0-75c175 0 316-141 316-316 0-176-141-317-316-317-176 0-317 141-317 317 0 175 141 316 317 316z m354-633a38 38 0 0 1-27-11 38 38 0 0 1 0-53l125-125a38 38 0 0 1 53 0 38 38 0 0 1 0 53l-125 125a38 38 0 0 1-26 11z" horiz-adv-x="1000" />
<glyph glyph-name="server" unicode="&#xe805;" d="M195 804c-81 0-149-67-149-149v-110c0-82 67-149 149-149h610c82 0 149 67 149 149v110c0 81-67 149-149 149z m0-75h610c41 0 74-34 74-74v-110c0-41-33-74-74-74h-610c-41 0-74 33-74 74v110c0 41 34 74 74 74z m55-50a38 38 0 0 1-37-37v-84a38 38 0 0 1 37-37 38 38 0 0 1 38 37v84a38 38 0 0 1-38 37z m167 0a38 38 0 0 1-38-37v-84a38 38 0 0 1 38-37 38 38 0 0 1 37 37v84a38 38 0 0 1-37 37z m166-41a38 38 0 0 1-37-38 38 38 0 0 1 37-37h167a38 38 0 0 1 38 37 38 38 0 0 1-38 38z m-388-334c-81 0-149-67-149-149v-110c0-82 67-149 149-149h610c82 0 149 67 149 149v110c0 81-67 149-149 149z m0-75h610c41 0 74-34 74-74v-110c0-41-33-74-74-74h-610c-41 0-74 33-74 74v110c0 41 34 74 74 74z m55-50a38 38 0 0 1-37-37v-84a38 38 0 0 1 37-37 38 38 0 0 1 38 37v84a38 38 0 0 1-38 37z m167 0a38 38 0 0 1-38-37v-84a38 38 0 0 1 38-37 38 38 0 0 1 37 37v84a38 38 0 0 1-37 37z m166-41a38 38 0 0 1-37-38 38 38 0 0 1 37-37h167a38 38 0 0 1 38 37 38 38 0 0 1-38 38z" horiz-adv-x="1000" />
<glyph glyph-name="sign-out" unicode="&#xe806;" d="M365 784c-98 0-175-20-227-72-52-51-71-128-71-227v-271c0-98 19-175 71-227 52-52 129-72 227-72h5c89 0 159 16 211 57 51 42 78 106 85 185a38 38 0 0 1-34 41 38 38 0 0 1-41-34c-6-67-25-107-57-133-32-26-84-41-164-41h-5c-88 0-142 18-174 50-32 32-49 86-49 174v271c0 89 17 142 49 174 32 32 86 50 174 50h5c80 0 132-15 165-41 32-26 51-67 57-136a38 38 0 0 1 40-34 38 38 0 0 1 35 40c-7 81-33 146-85 188-52 42-123 58-212 58z m391-257a38 38 0 0 1-26-11 38 38 0 0 1 0-53l75-75h-430a38 38 0 0 1-37-38 38 38 0 0 1 37-37h430l-75-76a38 38 0 0 1 0-53 38 38 0 0 1 53 0l139 140a38 38 0 0 1 0 53l-139 139a38 38 0 0 1-27 11z" horiz-adv-x="1000" />
<glyph glyph-name="favorite" unicode="&#xe807;" d="M500 801c-45 0-82-33-106-80a38 38 0 0 1 0 0l-73-147a38 38 0 0 1 0 0c-3-6-26-23-32-24l-133-22c-50-8-92-34-106-76-13-42 6-88 42-124l104-103c5-6 13-33 11-41l-29-128c-7-28-9-55-4-79 4-24 16-46 36-61 40-29 92-18 143 12l125 74c7 4 37 4 44 0a38 38 0 0 1 0 0l125-74a38 38 0 0 1 0 0c25-15 50-25 74-28 24-3 49 2 69 16 20 14 32 37 36 61 5 24 3 50-4 79l-29 128c-2 8 6 35 11 41l104 103c36 36 56 82 42 124-14 42-56 68-106 76l-133 22c-7 1-29 18-32 24a38 38 0 0 1 0 0l-73 146c-24 48-61 81-106 81z m0-75c7 0 22-6 39-39a38 38 0 0 1 0 0l73-146c0 0 0 0 0-1l0 0c17-35 48-57 86-64l133-22c35-5 45-18 48-25 2-7 1-23-24-48a38 38 0 0 1 0 0l-104-103c-29-30-40-70-31-110a38 38 0 0 1 0-1l29-127c5-22 6-39 4-49-2-10-5-13-7-14-2-2-5-4-16-2-10 1-26 6-45 18h0l-125 73c-38 23-82 23-120 1a38 38 0 0 1 0-1l-125-73c-38-23-57-19-61-16-2 1-5 4-7 14-1 10-1 27 4 49l29 127a38 38 0 0 1 0 1c10 40-2 80-31 110l-104 103c-24 25-26 41-23 48 2 7 12 20 47 25l133 22a38 38 0 0 1 0 0c38 7 68 29 86 65l73 146v0c16 32 32 39 39 39z" horiz-adv-x="1000" />
<glyph glyph-name="library" unicode="&#xe808;" d="M609 804c-44 0-83-9-110-36-27-28-36-66-36-110v-62h-62c-44 0-83-9-110-36-28-28-37-67-37-111v-61h-61c-44 0-83-9-111-37-27-27-36-66-36-111v-197c0-45 9-83 36-111 28-27 67-36 111-36h197c45 0 84 9 111 36 28 27 37 66 37 111v61h61c44 0 83 9 111 37 27 27 36 66 36 110v62h61c44 0 83 9 111 36 27 27 36 66 36 111v198c0 44-9 83-36 110-28 27-67 36-111 36z m0-75h198c34 0 50-6 58-14 8-8 14-23 14-57v-198c0-35-6-50-14-58-8-8-24-14-58-14h-198c-34 0-49 6-57 14-8 8-14 23-14 58v98 100c0 34 6 49 14 57 8 8 23 14 57 14z m-208-208h62v-61c0-45 9-84 36-111 27-27 66-36 110-36h62v-62c0-34-7-50-15-57-7-8-23-15-57-15h-99-99c0 0 0 0 0 0-4 0-8 0-12 1 0 0 0 0 0 0-4 0-7 0-10 0 0 0 0 0 0 0-7 1-12 2-17 4 0 0 0 0 0 0-9 2-15 6-18 10-8 7-15 23-15 57v99 99c0 34 7 50 15 57 7 8 23 15 57 15z m-208-208h61v-62c0-16 2-32 5-47 1-7 3-14 5-21 1-3 2-5 3-7 6-13 13-25 23-35 0 0 1 0 1 0 1-2 3-4 5-5 0 0 0 0 0 0 2-2 3-3 5-5 0 0 0 0 0 0 2-1 4-3 6-4 0 0 0 0 0 0 2-1 4-2 6-4 0 0 0 0 0 0 2-1 4-2 6-3 0 0 0 0 0 0 3-1 5-2 7-3 0 0 0 0 0 0 2-1 4-2 7-2 0-1 0 0 0 0 2-1 4-2 6-3 0 0 0 0 1 0 2-1 4-1 7-2 0 0 0 0 0 0 2 0 4-1 7-1 0 0 0 0 0 0 5-1 10-2 15-3 0 0 0 0 0 0 5-1 10-1 16-1 0 0 0 0 0 0 5-1 10-1 16-1 0 0 0 0 0 0h62v-61c0-34-7-50-15-58-8-8-23-14-58-14h-197c-34 0-50 6-58 14-7 8-14 24-14 58v197c0 35 7 50 14 58 8 8 24 15 58 15z" horiz-adv-x="1000" />
<glyph glyph-name="download" unicode="&#xe809;" d="M500 804a38 38 0 0 1-37-37v-493l-76 75a38 38 0 0 1-27 11 38 38 0 0 1-26-11 38 38 0 0 1 0-53l139-139a38 38 0 0 1 54 0l139 139a38 38 0 0 1 0 53 38 38 0 0 1-53 0l-75-75v493a38 38 0 0 1-38 37z m188-287a38 38 0 0 1-40-35 38 38 0 0 1 34-40c69-6 110-25 136-57 26-33 41-85 41-165v-5c0-88-18-142-50-174-32-32-85-49-174-49h-271c-88 0-141 17-174 49-32 32-49 86-49 174v5c0 80 14 132 40 164 26 32 66 51 134 57a38 38 0 0 1 34 41 38 38 0 0 1-41 34c-80-7-144-34-185-85-42-52-57-122-57-211v-5c0-98 20-175 71-227 52-52 129-71 227-71h271c99 0 176 19 227 71 52 52 72 129 72 227v5c0 89-16 160-58 212-42 52-107 78-188 85z" horiz-adv-x="1000" />
</font>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -0,0 +1,183 @@
import { ButtonAppearance } from '../button/button.interface';
export type PopupAppearance = 'default' | 'attention';
export type PopupTheme = 'dark' | 'light';
export interface PopupHeader {
title: string;
closable?: boolean;
}
export interface StrictPopupHeader extends PopupHeader {
title: string;
closable: boolean;
}
export interface PopupAction {
title: string;
event: string;
appearance?: ButtonAppearance;
}
export interface StrictPopupAction extends PopupAction {
title: string;
event: string;
appearance: ButtonAppearance;
}
export interface PopupOverlay {
closable?: boolean;
background?: string;
}
export interface StrictPopupOverlay extends PopupOverlay {
closable: boolean;
background: string;
}
export interface PopupConfig {
header?: PopupHeader | StrictPopupHeader;
actions?: PopupAction[] | StrictPopupAction[];
overlay?: PopupOverlay | StrictPopupOverlay;
body?: string;
appearance?: PopupAppearance;
theme?: PopupTheme;
}
export interface StrictPopupConfig extends PopupConfig {
header: StrictPopupHeader;
actions: StrictPopupAction[];
overlay: StrictPopupOverlay;
body?: string;
appearance: PopupAppearance;
theme: PopupTheme;
}
export class PopupConfiguration implements StrictPopupConfig {
private _header: StrictPopupHeader;
private _actions: StrictPopupAction[];
private _overlay: StrictPopupOverlay;
private _body?: string;
private _appearance: PopupAppearance;
private _theme: PopupTheme;
constructor(config?: PopupConfig) {
this._header = this.getHeaderConfig(config);
this._actions = this.getActionsConfig(config);
this._overlay = this.getOverlayConfig(config);
this._body = this.getBodyConfig(config);
this._appearance = this.getAppearanceConfig(config);
this._theme = this.getThemeConfig(config);
}
/**
* If the config object has a header object with a title property, return that, otherwise return
* 'Window'.
* @param {PopupConfig} [config] - PopupConfig - This is the configuration object that is passed to the
* popup.
* @returns An object with the properties title and closable.
*/
private getHeaderConfig(config?: PopupConfig) {
return <StrictPopupHeader>{
title: config?.header?.title ?? 'Window',
closable: config?.header?.closable ?? true,
};
}
/**
* It checks if the config has actions and if it does it is pushing the actions into the actions
* array. If the config doesn't have actions it is pushing the default actions into the actions array
* @param {PopupConfig} [config] - PopupConfig - This is the config object that is passed to the
* popup.
* @returns An array of PopupAction objects.
*/
private getActionsConfig(config?: PopupConfig): StrictPopupAction[] {
let actions: StrictPopupAction[] = [];
/* Checking if the config has actions and if it does it is pushing the actions into the actions array. */
if (config && config.actions) {
for (const action of config.actions) {
actions.push(<StrictPopupAction>{
title: action.title,
event: action.event,
appearance: action.appearance ?? 'default',
});
}
return actions;
}
/* Pushing the default actions into the actions array. */
actions.push(<StrictPopupAction>{
title: 'Cancel',
event: 'cancel',
appearance: 'flat',
});
actions.push(<StrictPopupAction>{
title: 'Submit',
event: 'submit',
appearance: 'primary',
});
return actions;
}
private getOverlayConfig(config?: PopupConfig) {
return <StrictPopupOverlay>{
closable: config?.overlay?.closable ?? 'true',
background: config?.overlay?.background ?? 'var(--sk-overlay)',
};
}
/**
* If the config object has an appearance property, return it, otherwise return 'default'.
* @param {PopupConfig} [config] - PopupConfig - This is the configuration object that is passed to the
* popup.
* @returns The appearance of the popup.
*/
private getAppearanceConfig(config?: PopupConfig) {
return <PopupAppearance>(config?.appearance ?? 'default');
}
/**
* If the config object has a body property, return that, otherwise return 'Content'.
* @param {PopupConfig} [config] - PopupConfig - This is the configuration object that we will pass to
* the popup.
* @returns The body of the popup.
*/
private getBodyConfig(config?: PopupConfig) {
return config?.body ?? 'Content';
}
private getThemeConfig(config?: PopupConfig) {
return config?.theme ?? 'dark';
}
get header() {
return this._header;
}
get actions() {
return this._actions;
}
get overlay() {
return this._overlay;
}
get body() {
return this._body;
}
get appearance() {
return this._appearance;
}
get theme() {
return this._theme;
}
set body(value: string | undefined) {
this._body = value;
}
}

View File

@ -1,20 +1,22 @@
<div class="popup-overlay" [ngClass]="{'shown': loaded, 'hiding': hiding}">
<div class="popup-window-wrapper">
<div class="popup-overlay" (click)="closeViaClick($event)" [attr.style]="'--local-overlay:' + config.overlay.background" [ngClass]="{'shown': loaded, 'hiding': hiding}" skirdaKeyboard (escape)="closeViaEscape($event)">
<div class="popup-window-wrapper" [attr.data-appearance]="config.appearance" [attr.data-theme]="config.theme">
<div class="popup-window">
<div class="popup-head">
<div class="head-title">Notification</div>
<div class="head-close" (click)="cancel.emit()">
<skirda-icon name="sign-out" size="18"></skirda-icon>
<div class="head-title">{{ config.header.title }}</div>
<div class="head-close" (click)="event.emit('close')" *ngIf="config.header.closable">
<skirda-icon name="close" size="20"></skirda-icon>
</div>
</div>
<div class="popup-body">
<div class="popup-body" *ngIf="!config.body">
<ng-template skirdaPopup></ng-template>
</div>
<div class="popup-body" *ngIf="config.body">
{{config.body}}
</div>
<div class="popup-actions">
<skirda-button appearance="flat" (click)="cancel.emit()">Cancel</skirda-button>
<skirda-button (click)="confirm.emit()">Confirm</skirda-button>
<div class="popup-actions" *ngIf="config.actions.length">
<skirda-button [appearance]="action.appearance" (click)="event.emit(action.event)" *ngFor="let action of config.actions">{{ action.title }}</skirda-button>
</div>
</div>
</div>

View File

@ -1,4 +1,4 @@
:host {
:host::ng-deep {
position: absolute;
@keyframes show {
@ -48,7 +48,7 @@
left: 0;
width: 100%;
height: 100vh;
background-color: rgba(0,0,0,0.5);
background-color: var(--local-overlay, var(--sk-overlay));
display: flex;
justify-content: center;
align-items: center;
@ -71,27 +71,45 @@
.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;
border-radius: 12px;
overflow: hidden;
translate: 0px 20px;
opacity: 0;
box-shadow: 0px 10px 32px 0px rgba(0,0,0,0.15);
&[data-appearance="attention"] {
box-shadow: 0px 0px 0px 1.5px red;
}
&[data-theme="dark"] {
--local-background: #222;
--local-color: #fff;
--local-border: rgba(255, 255, 255, 0.125);
background: linear-gradient(45deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.25));
}
&[data-theme="light"] {
--local-background: #fff;
--local-color: #111;
--local-border: rgba(0, 0, 0, 0.125);
background: linear-gradient(45deg, rgba(0, 0, 0, 0.15), rgba(0, 0, 0, 0.25));
}
.popup-window {
border-radius: 7px;
background-color: #222;
border-radius: 11px;
background-color: var(--local-background);
color: var(--local-color);
.popup-head {
padding: 1rem;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
border-bottom: 1px solid var(--local-border);
.head-title {
font-size: 1rem;
color: #aaa;
font-weight: 500;
}
.head-close {
@ -103,19 +121,28 @@
.popup-body {
padding: 2rem;
text-align: center;
line-height: 140%;
}
.popup-actions {
border-top: 1px solid rgba(255, 255, 255, 0.1);
border-top: 1px solid var(--local-border);
display: flex;
align-items: center;
padding: 1rem;
gap: 0.25rem;
gap: 0.5rem;
justify-content: flex-end;
}
}
}
}
}
:host::ng-deep {
skirda-button button[data-appearance="outline"], skirda-button button[data-appearance="flat"] {
color: var(--local-color)!important;
}
skirda-button button[data-appearance="outline"] {
box-shadow: 0px 0px 0px 1px var(--local-border)!important;
}
}

View File

@ -2,12 +2,13 @@ import {
AfterViewInit,
Component,
EventEmitter,
Input,
OnInit,
Output,
TemplateRef,
ViewChild,
ViewContainerRef,
} from '@angular/core';
import { PopupConfiguration } from './popup.class';
import { PopupDirective } from './popup.directive';
@Component({
@ -16,16 +17,16 @@ import { PopupDirective } from './popup.directive';
styleUrls: ['./popup.component.scss'],
})
export class PopupComponent implements OnInit, AfterViewInit {
@Input() config: PopupConfiguration = new PopupConfiguration();
loaded: boolean = false;
hiding: boolean = false;
contentQueue?: TemplateRef<any>;
@Output() cancel: EventEmitter<void> = new EventEmitter();
@Output() confirm: EventEmitter<void> = new EventEmitter();
@Output() event: EventEmitter<string> = new EventEmitter();
@ViewChild(PopupDirective) private popupContent!: PopupDirective;
constructor(private viewContainerRef: ViewContainerRef) {}
constructor() {}
ngOnInit(): void {}
@ -42,14 +43,29 @@ export class PopupComponent implements OnInit, AfterViewInit {
if (!template) return;
if (!this.popupContent) {
this.contentQueue = template;
this.config.body = undefined;
return;
}
this.popupContent.viewContainerRef.createEmbeddedView(template);
this.config.body = undefined;
}
hide() {
this.loaded = false;
this.hiding = true;
}
close() {
console.log('close');
}
closeViaEscape(event: KeyboardEvent) {
if (this.config.overlay.closable) this.event.emit('cancel');
}
closeViaClick(event: MouseEvent) {
if (this.config.overlay.closable && event.target === event.currentTarget)
this.event.emit('cancel');
}
}

View File

@ -1,4 +1,4 @@
import { Directive, ViewContainerRef } from '@angular/core';
import { Directive, HostListener, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[skirdaPopup]',

View File

@ -4,10 +4,11 @@ import { PopupComponent } from './popup.component';
import { PopupDirective } from './popup.directive';
import { ButtonModule } from '../button/button.module';
import { IconModule } from '../icon/icon.module';
import { DirectivesModule } from '../directives/directives.module';
@NgModule({
declarations: [PopupComponent, PopupDirective],
imports: [CommonModule, ButtonModule, IconModule],
imports: [CommonModule, ButtonModule, IconModule, DirectivesModule],
exports: [PopupComponent, PopupDirective],
})
export class PopupModule {}

View File

@ -7,6 +7,7 @@ import {
ViewChild,
} from '@angular/core';
import { first } from 'rxjs';
import { PopupConfig, PopupConfiguration } from './popup.class';
import { PopupComponent } from './popup.component';
import { PopupDirective } from './popup.directive';
@ -18,7 +19,11 @@ export class PopupService {
constructor() {}
open(portal: PopupDirective, template?: TemplateRef<any>) {
open(
portal: PopupDirective,
template?: TemplateRef<any>,
config?: PopupConfig
) {
let container = portal.viewContainerRef;
container.clear();
@ -26,15 +31,14 @@ export class PopupService {
this.instance = componentRef.instance;
this.instance.confirm.pipe(first()).subscribe(() => {
this.hide(componentRef);
});
this.instance.cancel.pipe(first()).subscribe(() => {
this.instance.config = new PopupConfiguration(config);
this.instance.event.pipe(first()).subscribe((event) => {
this.hide(componentRef);
});
this.instance.load(template);
return this.instance;
return this.instance.event;
}
hide(componentRef: ComponentRef<PopupComponent>) {

View File

@ -5,8 +5,9 @@
}
.sk-tag {
display: inline-block;
padding: 0px var(--sk-gap-m);
display: inline-flex;
align-items: center;
padding: 1px var(--sk-gap-m);
border-radius: var(--sk-br-s);
background-color: rgba(255, 255, 255, 0.05);
}

View File

@ -11,6 +11,7 @@ import { TagModule } from './tag/tag.module';
import { PipesModule } from './pipes/pipes.module';
import { GameModule } from './game/game.module';
import { PopupModule } from '../public-api';
import { DirectivesModule } from './directives/directives.module';
@NgModule({
declarations: [],
@ -27,6 +28,7 @@ import { PopupModule } from '../public-api';
PipesModule,
GameModule,
PopupModule,
DirectivesModule,
],
exports: [
IconModule,
@ -41,6 +43,7 @@ import { PopupModule } from '../public-api';
PipesModule,
GameModule,
PopupModule,
DirectivesModule,
],
})
export class UiModule {}

View File

@ -1,7 +1,7 @@
<menu>
<div class="sk-search-panel">
<skirda-input [formControl]="search" size="l" placeholder="Quick search">
<skirda-icon name="search" size="16" role="left"></skirda-icon>
<skirda-icon name="search" size="18" role="left"></skirda-icon>
</skirda-input>
<button>
<skirda-icon name="menu-panel" color="var(--sk-primary)"></skirda-icon>
@ -16,7 +16,7 @@
</skirda-section>
<skirda-section [routerLink]="['games']" routerLinkActive="active">
<skirda-icon name="library"></skirda-icon>
<skirda-heading size="6">Games</skirda-heading>
<skirda-heading size="6">Library</skirda-heading>
</skirda-section>
<skirda-section [routerLink]="['friends']" routerLinkActive="active">
<skirda-icon name="friends"></skirda-icon>

View File

@ -9,7 +9,7 @@
flex-direction: column;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.4);
background-color: rgba(0,0,0,0.65);
padding: 2rem 0.5rem 0.5rem 0.5rem;
box-sizing: border-box;
backdrop-filter: blur(64px);
@ -33,6 +33,13 @@
appearance: none;
background: none;
border: 0;
transition: 0.1s ease;
border-radius: var(--sk-br-m);
cursor: pointer;
&:hover {
background-color: rgba(255, 255, 255, 0.05);
}
}
}

View File

@ -23,9 +23,9 @@
.content {
flex: 1;
background-color: rgba(0,0,0,0.05);
background-color: rgba(0,0,0,0.15);
display: flex;
backdrop-filter: blur(1rem);
backdrop-filter: blur(2rem);
overflow-y: auto;
}
}

View File

@ -6,7 +6,7 @@ import { Component, OnInit } from '@angular/core';
styleUrls: ['./main-root.component.scss'],
})
export class MainRootComponent implements OnInit {
image: string = 'assets/games/minecraft/backgrounds/5.webp';
image: string = 'assets/games/minecraft/backgrounds/7.webp';
constructor() {}

View File

@ -1,7 +1,13 @@
@mixin page {
width: 100%;
.section {
padding: 3rem;
flex: 1;
box-sizing: border-box;
width: 100%;
height: 100%;
// background-color: #fff;
.section-head {
@ -14,4 +20,4 @@
padding: var(--sk-gap-xl) 0rem;
}
}
}
}

View File

@ -12,13 +12,13 @@
<div class="head-subtitle">Game page will be here</div>
</div>
<div class="section-content">
<!-- <skirda-button (click)="openPopup(popupContent)">
<skirda-icon name="play" size="16"></skirda-icon>
Run game
</skirda-button> -->
<skirda-button>
<skirda-button (click)="openPopup(popupContent)">
<skirda-icon name="play" size="16"></skirda-icon>
Run game
</skirda-button>
<!-- <skirda-button>
<skirda-icon name="play" size="16"></skirda-icon>
Run game
</skirda-button> -->
</div>
</div>

View File

@ -1,29 +1,66 @@
import { TemplateRef, ViewChild } from '@angular/core';
import { OnDestroy, TemplateRef, ViewChild } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { PopupConfiguration } from 'projects/ui/src/lib/popup/popup.class';
import { PopupDirective } from 'projects/ui/src/lib/popup/popup.directive';
import { PopupService } from 'projects/ui/src/lib/popup/popup.service';
import { first } from 'rxjs';
import { first, Subscription } from 'rxjs';
@Component({
selector: 'app-game-page',
templateUrl: './game-page.component.html',
styleUrls: ['./game-page.component.scss'],
})
export class GamePageComponent implements OnInit {
export class GamePageComponent implements OnInit, OnDestroy {
@ViewChild(PopupDirective, { static: true }) popupPortal!: PopupDirective;
subs: Map<string, Subscription> = new Map();
constructor(private popup: PopupService) {}
ngOnInit(): void {}
openPopup(template: TemplateRef<any>) {
let dialog = this.popup.open(this.popupPortal, template);
ngOnDestroy(): void {
this.subs.forEach((value) => value.unsubscribe());
}
dialog.cancel.pipe(first()).subscribe(() => {
console.log('cancel clicked');
});
dialog.confirm.pipe(first()).subscribe(() => {
console.log('confirm clicked');
});
ngAfterViewInit(): void {
//Called after ngAfterContentInit when the component's view has been initialized. Applies to components only.
//Add 'implements AfterViewInit' to the class.
// this.openPopup();
}
openPopup(template?: TemplateRef<any>) {
this.subs.set(
'popup-events',
this.popup
.open(this.popupPortal, undefined, {
header: { closable: false, title: 'Warning' },
actions: [
{
title: 'I understand, delete file',
event: 'delete',
appearance: 'primary',
},
{
title: 'Do not delete',
event: 'cancel',
appearance: 'outline',
},
// {
// title: 'Primary button',
// event: 'button-2',
// appearance: 'primary',
// },
],
overlay: {
closable: true,
// background: 'rgba(255, 255, 255, 1)',
},
body: 'Humblebrag chillwave sriracha, ramps polaroid distillery edison bulb palo santo etsy sus pabst knausgaard typewriter dreamcatcher.',
theme: 'light',
})
.subscribe((event) => {
console.log(`event: ${event}`);
})
);
}
}

View File

@ -2,7 +2,7 @@ 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';
import { first, Subscription } from 'rxjs';
@Component({
selector: 'app-sandbox',
@ -17,6 +17,11 @@ export class SandboxComponent implements OnInit {
age: new FormControl<number>(0),
});
@ViewChild(PopupDirective, { static: true }) popupPortal!: PopupDirective;
subs: Map<string, Subscription> = new Map();
ngOnDestroy(): void {
this.subs.forEach((value) => value.unsubscribe());
}
constructor(private popup: PopupService) {}
@ -27,13 +32,11 @@ export class SandboxComponent implements OnInit {
}
openPopup(template: TemplateRef<any>) {
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');
});
this.subs.set(
'popup-events',
this.popup.open(this.popupPortal, template).subscribe((event) => {
console.log(`event: ${event}`);
})
);
}
}

View File

@ -12,7 +12,7 @@ const routes: Routes = [
component: PlaygroundComponent,
},
{
path: 'main',
path: '',
loadChildren: () => MainRoutingModule,
},
{
@ -24,7 +24,7 @@ const routes: Routes = [
component: SignInComponent,
},
{
path: '',
path: 'loading',
component: LoadingScreenComponent,
},
];

View File

@ -22,11 +22,16 @@ button, input, textarea {
// colors
--sk-input: rgba(18,18,18,0.5);
--sk-input-focus: rgba(18,18,18,0.9);
--sk-primary: #24927a;
--sk-secondary: #1b557d;
--sk-primary-dark: #2A3B39;
--sk-primary: #d62828ff;
--sk-secondary: #f77f00ff;
// border-radius
--sk-br-s: 0.25rem;
--sk-br-m: 0.5rem;
--sk-palette-1: #ffbe0b;
--sk-palette-2: #fb5607;
--sk-palette-3: #ff006e;
--sk-palette-4: #8338ec;
--sk-palette-5: #3a86ff;
--sk-overlay: rgba(0,0,0,0.5);
}