Merge branch 'new-theme' into new-theme-linking

This commit is contained in:
argirok 2022-02-25 16:52:30 +02:00
commit 9e961d46c1
23 changed files with 335 additions and 187 deletions

View File

@ -1,62 +1,69 @@
<h1 *ngIf="formTitle" class="uk-margin-auto">{{formTitle}}</h1>
<ng-content select="[page-title]"></ng-content>
<ng-content select="[page-description]"></ng-content>
<div *ngIf="errorMessage" class="uk-width-1-1 uk-alert uk-alert-danger uk-text-center"
role="alert">{{errorMessage}}</div>
<div class="uk-margin-top" uk-grid [formGroup]="contactForm">
<div *ngIf="contactForm.get('name')" class="uk-width-1-2@s uk-margin-medium-top">
<input class="uk-input" type="text" placeholder="Name *" formControlName="name"
<div class="uk-child-width-1-1 uk-grid" [class.uk-grid-medium]="smallForm"
[class.uk-grid-margin-large]="!smallForm" [class.uk-child-width-1-2@s]="!smallForm"
[formGroup]="contactForm" uk-grid>
<div *ngIf="contactForm.get('name')">
<input class="uk-input" type="text" placeholder="Name *" formControlName="name"
[class.uk-form-danger]="contactForm.get('name').invalid && contactForm.get('name').touched">
</div>
<div *ngIf="contactForm.get('surname')" class="uk-width-1-2@s uk-margin-medium-top">
<input class="uk-input" type="text" placeholder="Surname *" formControlName="surname"
[class.uk-form-danger]="contactForm.get('surname').invalid && contactForm.get('surname').touched">
</div>
<div *ngIf="contactForm.get('email')" class="uk-width-1-2@s uk-margin-medium-top">
<input class="uk-input" type="text" placeholder="Email *" formControlName="email"
[class.uk-form-danger]="contactForm.get('email').invalid && contactForm.get('email').touched">
</div>
<div *ngIf="contactForm.get('job')" class="uk-width-1-2@s uk-margin-medium-top">
<input class="uk-input" type="text" placeholder="Job Title *" formControlName="job"
[class.uk-form-danger]="contactForm.get('job').invalid && contactForm.get('job').touched">
</div>
<div *ngIf="contactForm.get('affiliation')" class="uk-width-1-2@s uk-margin-medium-top">
<input class="uk-input" type="text" placeholder="Affiliation *" formControlName="affiliation"
[class.uk-form-danger]="contactForm.get('affiliation').invalid && contactForm.get('affiliation').touched">
</div>
<div *ngIf="contactForm.get('community')" class="uk-width-1-2@s uk-margin-medium-top">
<input class="uk-input uk-width-1" type="text" placeholder="Research Community or Infrastructure *" formControlName="community"
[class.uk-form-danger]="contactForm.get('community').invalid && contactForm.get('community').touched">
</div>
<div *ngIf="contactForm.get('organization')" class="uk-width-1-2@s uk-margin-medium-top">
<input class="uk-input uk-width-1-1" type="text" placeholder="Organization *" formControlName="organization"
[class.uk-form-danger]="contactForm.get('organization').invalid && contactForm.get('organization').touched">
</div>
<div *ngIf="contactForm.get('organizationType')" class="uk-width-1-2@s uk-margin-medium-top">
<select class="uk-select uk-width-1-1" formControlName="organizationType">
<option [value]="''" hidden selected>Organization Type *</option>
<option *ngFor="let option of organizationTypes" [value]="option">{{option}}</option>
</select>
</div>
<div *ngIf="contactForm.get('subject')" class="uk-width-1-1@s uk-margin-medium-top">
<input class="uk-input uk-width-1-1" type="text" placeholder="Subject *" formControlName="subject"
[class.uk-form-danger]="contactForm.get('subject').invalid && contactForm.get('subject').touched">
</div>
<div *ngIf="contactForm.get('message')" class="uk-width-1-1 uk-margin-medium-top">
</div>
<div *ngIf="contactForm.get('surname')">
<input class="uk-input" type="text" placeholder="Surname *" formControlName="surname"
[class.uk-form-danger]="contactForm.get('surname').invalid && contactForm.get('surname').touched">
</div>
<div *ngIf="contactForm.get('email')">
<input class="uk-input" type="text" placeholder="Email *" formControlName="email"
[class.uk-form-danger]="contactForm.get('email').invalid && contactForm.get('email').touched">
</div>
<div *ngIf="contactForm.get('job')">
<input class="uk-input" type="text" placeholder="Job Title *" formControlName="job"
[class.uk-form-danger]="contactForm.get('job').invalid && contactForm.get('job').touched">
</div>
<div *ngIf="contactForm.get('affiliation')">
<input class="uk-input" type="text" placeholder="Affiliation *" formControlName="affiliation"
[class.uk-form-danger]="contactForm.get('affiliation').invalid && contactForm.get('affiliation').touched">
</div>
<div *ngIf="contactForm.get('community')">
<input class="uk-input uk-width-1" type="text" placeholder="Research Community or Infrastructure *"
formControlName="community"
[class.uk-form-danger]="contactForm.get('community').invalid && contactForm.get('community').touched">
</div>
<div *ngIf="contactForm.get('organization')">
<input class="uk-input uk-width-1-1" type="text" placeholder="Organization *" formControlName="organization"
[class.uk-form-danger]="contactForm.get('organization').invalid && contactForm.get('organization').touched">
</div>
<div *ngIf="contactForm.get('organizationType')">
<select class="uk-select uk-width-1-1" formControlName="organizationType">
<option [value]="''" hidden selected>Organization Type *</option>
<option *ngFor="let option of organizationTypes" [value]="option">{{option}}</option>
</select>
</div>
<div *ngIf="contactForm.get('subject')" class="uk-width-1-1">
<input class="uk-input uk-width-1-1" type="text" placeholder="Subject *" formControlName="subject"
[class.uk-form-danger]="contactForm.get('subject').invalid && contactForm.get('subject').touched">
</div>
<div *ngIf="contactForm.get('message')" class="uk-width-1-1">
<textarea rows="4" class="uk-textarea" placeholder="Comments *" formControlName="message"
[class.uk-form-danger]="contactForm.get('message').invalid && contactForm.get('message').touched">
</textarea>
</div>
<div *ngIf="contactForm.get('description')" class="uk-width-1-1 uk-margin-medium-top">
</div>
<div *ngIf="contactForm.get('description')" class="uk-width-1-1">
<textarea rows="4" class="uk-textarea" placeholder="Description *" formControlName="description"
[class.uk-form-danger]="contactForm.get('description').invalid && contactForm.get('description').touched">
</textarea>
</div>
<div *ngIf="contactForm.get('recaptcha')" class="uk-width-1-2@s uk-margin-top">
<re-captcha (resolved)="handleRecaptcha($event)" [(siteKey)]="properties.reCaptchaSiteKey">
</re-captcha>
</div>
<div class="uk-margin-medium-top uk-width-1-1">
<button class="uk-button uk-text-uppercase" [class.uk-button-primary]="!buttonClass" [ngClass]="buttonClass" (click)="send()">Send</button>
</div>
</div>
<div *ngIf="contactForm.get('recaptcha')" class="uk-width-1-1">
<re-captcha class="uk-flex " [ngClass]="'uk-flex-' + alignButton" (resolved)="handleRecaptcha($event)" [(siteKey)]="properties.reCaptchaSiteKey">
</re-captcha>
</div>
<div class="uk-width-1-1 uk-flex" [ngClass]="'uk-flex-' + alignButton">
<button class="uk-button uk-text-uppercase uk-flex uk-flex-middle"
[class.uk-disabled]="contactForm.invalid || sending"
[class.uk-button-primary]="!buttonClass && contactForm.valid" [ngClass]="(contactForm.valid?buttonClass:'')"
(click)="send()">
{{sendButton}}
<span *ngIf="sending" class="uk-icon uk-margin-small-left"><loading [top_margin]="false" [size]="'small'" [color]="null"></loading></span>
</button>
</div>
</div>

View File

@ -1,8 +1,7 @@
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {Component, EventEmitter, Input, Output} from '@angular/core';
import {FormGroup} from '@angular/forms';
import {EnvProperties} from "../utils/properties/env-properties";
import {Observable} from "rxjs";
import {map, startWith} from "rxjs/operators";
import {properties} from "../../../environments/environment";
@Component({
selector: 'contact-us',
@ -10,18 +9,16 @@ import {map, startWith} from "rxjs/operators";
})
export class ContactUsComponent {
@Input()
public contactForm: FormGroup;
@Input() formTitle: string;
@Input() properties: EnvProperties;
@Input() public contactForm: FormGroup;
@Input() public formTitle: string;
@Input() public organizationTypes: string[];
@Input() public buttonClass: string;
@Input() public alignButton: "left" | "right" | "center" = "left";
@Input() public sendButton: string = "Send";
@Input() public smallForm: boolean = false;
@Input() public sending: boolean = false;
@Output() sendEmitter: EventEmitter<any> = new EventEmitter<any>();
@Input() errorMessage;
@Input()
public organizationTypes: string[];
@Input()
public right: boolean = true;
@Input()
public buttonClass: string;
public properties: EnvProperties = properties;
public send() {
this.sendEmitter.emit({

View File

@ -7,11 +7,12 @@ import {ReactiveFormsModule} from "@angular/forms";
import {MatAutocompleteModule} from "@angular/material/autocomplete";
import {RecaptchaModule} from "ng-recaptcha";
import {SafeHtmlPipeModule} from "../utils/pipes/safeHTMLPipe.module";
import {LoadingModule} from "../utils/loading/loading.module";
@NgModule({
imports: [
CommonModule, RouterModule,
ReactiveFormsModule, MatAutocompleteModule, RecaptchaModule, SafeHtmlPipeModule],
ReactiveFormsModule, MatAutocompleteModule, RecaptchaModule, SafeHtmlPipeModule, LoadingModule],
declarations: [
ContactUsComponent
],

View File

@ -5,6 +5,8 @@
.how .first > div:first-child:after {
content: "we";
font-size: 20px;
font-weight: 600;
text-align: center;
padding-bottom: 5%;
position: absolute;
@ -19,17 +21,19 @@
.how .second > div:first-child {
position: relative;
padding: 0 22% 0 22%;
padding: 0 10% 0 20%;
}
.how .second > div:first-child:after {
content: "and";
font-size: 20px;
font-weight: 600;
text-align: center;
padding-bottom: 5%;
position: absolute;
background-image: url("~src/assets/common-assets/monitor-assets/green-arrows/2.svg");
right: -10%;
top: 31%;
right: -17%;
top: 33%;
width: 30%;
background-size: contain;
background-repeat: no-repeat;
@ -41,20 +45,22 @@
}
.how .third > div:first-child {
padding: 0 12% 0 12%;
padding: 0 14% 0 13%;
}
.how .third:after {
content: "on which";
font-size: 20px;
font-weight: 600;
padding-right: 30%;
padding-top: 5%;
padding-bottom: 5%;
position: absolute;
background-image: url("~src/assets/common-assets/monitor-assets/green-arrows/3.svg");
bottom: 6%;
left: 6%;
bottom: -6%;
left: 13%;
transform: translateY(100%);
width: 55%;
width: 140px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
@ -66,17 +72,19 @@
.how .fourth > div:first-child {
position: relative;
padding: 0 15% 0 15%;
padding: 0 16% 0 16%;
}
.how .fourth> div:first-child:after {
content: "and";
font-size: 20px;
font-weight: 600;
text-align: center;
padding-bottom: 5%;
position: absolute;
background-image: url("~src/assets/common-assets/monitor-assets/green-arrows/4.svg");
left: -18%;
top: 35%;
top: 36%;
width: 30%;
background-size: contain;
background-repeat: no-repeat;
@ -84,7 +92,7 @@
}
.how .fifth {
padding: 10% 2% 0 2%;
padding: 11% 2% 0 2%;
}
.how .fifth > div:first-child {
@ -93,6 +101,8 @@
.how .fifth > div:first-child:after {
content: "We";
font-size: 20px;
font-weight: 600;
text-align: center;
padding-bottom: 5%;
position: absolute;
@ -125,7 +135,7 @@
content: "";
position: absolute;
background-image: url("~src/assets/common-assets/monitor-assets/green-arrows/6.svg");
left: -20%;
left: -26%;
top: -20%;
height: 70%;
width: 30%;
@ -136,32 +146,17 @@
.how .final > div:first-child:after {
content: "We make visualizations, graphs, reports and deliver all in a customisable tool";
font-size: 20px;
position: absolute;
background-image: url("~src/assets/common-assets/monitor-assets/how/circle.png");
right: -220px;
top: -20%;
width: 300px;
padding: 8% 0 5% 220px;
top: 30%;
width: 250px;
padding: 8% 0 5% 0;
background-size: contain;
background-repeat: no-repeat;
background-position: bottom center;
}
}
@media only screen and (min-width: 960px) {
.how .third:after {
bottom: -6%;
}
}
@media only screen and (min-width: 1200px) {
.how .third:after {
bottom: -10%;
left: 25%;
width: 25%;
}
}
@media only screen and (max-width: 639px) {
.how .first {
position: relative;
@ -171,11 +166,11 @@
.how .first:after {
content: "we";
text-align: center;
padding: 25px 105px 25px 0;
padding: 10% 34% 10% 0;
position: absolute;
background-image: url("~src/assets/common-assets/monitor-assets/green-arrows/3.svg");
left: 26%;
top: 72%;
top: 79%;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
@ -183,17 +178,17 @@
.how .second {
position: relative;
padding: 0 15% 30% 15%;
padding: 0 10% 30% 10%;
}
.how .second:after {
content: "and";
text-align: center;
padding: 25px 105px 25px 0;
padding: 10% 34% 10% 0;
position: absolute;
background-image: url("~src/assets/common-assets/monitor-assets/green-arrows/3.svg");
left: 25%;
top: 70%;
top: 80%;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
@ -206,12 +201,13 @@
.how .third:after {
content: "on which";
font-weight: bold;
text-align: center;
padding: 25px 105px 25px 0;
padding: 10% 41% 10% 0;
position: absolute;
background-image: url("~src/assets/common-assets/monitor-assets/green-arrows/3.svg");
left: 17%;
top: 75%;
left: 15%;
top: 83%;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
@ -229,7 +225,7 @@
.how .fourth:after {
content: "and";
text-align: center;
padding: 25px 105px 25px 0;
padding: 10% 34% 10% 0;
position: absolute;
background-image: url("~src/assets/common-assets/monitor-assets/green-arrows/3.svg");
left: 26%;
@ -247,7 +243,7 @@
.how .fifth:after {
content: "We";
text-align: center;
padding: 25px 105px 25px 0;
padding: 10% 34% 10% 0;
position: absolute;
background-image: url("~src/assets/common-assets/monitor-assets/green-arrows/3.svg");
left: 27%;
@ -277,8 +273,8 @@
content: "";
position: absolute;
background-image: url("~src/assets/common-assets/monitor-assets/green-arrows/6.svg");
left: 32%;
top: -80%;
left: 34%;
top: -70%;
height: 70%;
width: 30%;
background-size: contain;
@ -288,12 +284,12 @@
.how .final > div:first-child:after {
content: "We make visualizations, graphs, reports and deliver all in a customisable tool";
text-align: center;
position: absolute;
background-image: url("~src/assets/common-assets/monitor-assets/how/circle.png");
left: -62%;
top: 85%;
width: 300px;
padding: 12% 0 0 70%;
padding: 12% 0 0 54%;
background-size: contain;
background-repeat: no-repeat;
background-position: center;

View File

@ -9,7 +9,7 @@ import {Component} from "@angular/core";
<div>
<img src="assets/common-assets/monitor-assets/how/1.png" loading="lazy">
</div>
<div class="uk-text-center">
<div class="uk-text-center uk-text-large">
<span class="uk-text-uppercase uk-text-bold">Starting</span> from existing<br>research-related data sources
</div>
</div>
@ -22,7 +22,7 @@ import {Component} from "@angular/core";
<div>
<img src="assets/common-assets/monitor-assets/how/3.png" loading="lazy">
</div>
<div class="uk-text-center">
<div class="uk-text-center uk-text-large">
build an open, global<br>and trusted Research graph
</div>
</div>

View File

@ -112,7 +112,7 @@
' uk-position-relative ' :(' uk-section ' ))+'}':null)">
<div [class]="' uk-background-norepeat uk-background-bottom-center uk-padding-remove-bottom uk-flex uk-flex-middle uk-background-fixed '+searchFormClass
+ (usedBy != 'deposit' && usedBy != 'orcid' && (!customFilter || customFilter.queryFieldName != 'communityId') && !dashboard ?
' image-front-topbar searchFormMinHeight uk-padding-remove-bottom uk-section' : '')
' image-front-topbar searchFormMinHeight uk-padding-remove-bottom uk-section uk-section-small' : '')
+(simpleView?'':' advancedSearchFormBackground ')">
<!-- TODO - Kostis until here-->
<div class="uk-width-1-1">
@ -122,7 +122,7 @@
</div>
</div>
<div class="uk-position-relative">
<div class="uk-container uk-container-large uk-section" id="searchForm">
<div class="uk-container uk-container-large uk-section uk-section-small uk-margin-bottom" id="searchForm">
<advanced-search-form
[entityType]="entityType"
[fieldIds]="fieldIds"

View File

@ -98,7 +98,7 @@
</modal-alert>
<ng-template #resultPreview let-result="result">
<div class="uk-flex uk-flex-center">
<img *ngIf="result.logoUrl" [src]="result | logoUrl"
<img *ngIf="result.logoUrl" [src]="result | logoUrl" class="uk-blend-multiply"
[alt]="((result.title)?result.title:result.shortTitle) + ' logo'" loading="lazy">
</div>
</ng-template>

View File

@ -23,7 +23,7 @@ export class PortalSearchResultComponent implements OnInit{
@ViewChild('AlertModal') modal;
visibilityIcon: Map<Visibility, string> = new Map<Visibility, string> ([
["PRIVATE", 'incognito'],
["RESTRICTED", 'group']
["RESTRICTED", 'restricted']
]);
public urlParam: string;
public errorCodes: ErrorCodes = new ErrorCodes();

View File

@ -9,7 +9,7 @@ import {ManageModule} from "../../utils/manage/manage.module";
import {IconsModule} from "../../utils/icons/icons.module";
import {UrlPrefixModule} from "../../utils/pipes/url-prefix.module";
import {IconsService} from "../../utils/icons/icons.service";
import {incognito} from "../../utils/icons/icons";
import {incognito, restricted} from "../../utils/icons/icons";
import {LogoUrlPipeModule} from "../../utils/pipes/logoUrlPipe.module";
@NgModule({
@ -29,6 +29,6 @@ import {LogoUrlPipeModule} from "../../utils/pipes/logoUrlPipe.module";
})
export class PortalSearchResultModule {
constructor(private iconsService: IconsService) {
this.iconsService.registerIcons([incognito])
this.iconsService.registerIcons([incognito, restricted])
}
}

View File

@ -0,0 +1,35 @@
.quick-contact {
position: fixed;
bottom: 5vh;
right: 5vw;
}
.uk-card > .uk-background-secondary:first-child {
border-radius: 4px 4px 0 0;
}
.uk-drop {
width: 380px;
}
.avatars > img {
width: 50px;
height: 50px;
object-fit: cover;
border: 2px solid #fff;
}
.avatars > img:nth-child(n+1) {
margin-left: -5px;
}
/* hide scrollbar but allow scrolling */
.uk-overflow-auto {
-ms-overflow-style: none; /* for Internet Explorer, Edge */
scrollbar-width: none; /* for Firefox */
overflow-y: scroll;
}
.uk-overflow-auto::-webkit-scrollbar {
display: none; /* for Chrome, Safari, and Opera */
}

View File

@ -0,0 +1,31 @@
<div class="quick-contact">
<a class="uk-button uk-button-secondary uk-text-uppercase uk-flex uk-flex-middle" (click)="toggleModal()">
<icon *ngIf="!showForm" name="mail" [flex]="true"></icon>
<icon *ngIf="showForm" name="close" [flex]="true"></icon>
<span class="uk-margin-small-left">Contact</span>
</a>
<div #drop id="quick-contact" class="uk-card uk-card-default uk-drop" uk-drop="mode: click; pos: top-right; animation: uk-animation-fade">
<div class="uk-background-secondary uk-padding-small uk-text-center">
<div class="uk-text-small">
Send a message
</div>
<div class="uk-margin-small avatars">
<img class="uk-border-circle" src="assets/monitor-assets/avatar.jpg">
<img class="uk-border-circle" src="assets/monitor-assets/avatar.jpg">
<img class="uk-border-circle" src="assets/monitor-assets/avatar.jpg">
<img class="uk-border-circle" src="assets/monitor-assets/avatar.jpg">
</div>
<div class="uk-text-bold">
How can we help?
</div>
<div class="uk-text-small">
We usually respond in a few hours.
</div>
</div>
<div class="uk-height-medium uk-card-body uk-overflow-auto">
<loading *ngIf="sending" class="uk-margin-xlarge-top"></loading>
<contact-us *ngIf="contactForm && !sending" [organizationTypes]="organizationTypes" (sendEmitter)="send($event)"
[smallForm]="true" alignButton="center" sendButton="Send Message" [contactForm]="contactForm"></contact-us>
</div>
</div>
</div>

View File

@ -0,0 +1,55 @@
import {Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild} from '@angular/core';
import {FormGroup} from "@angular/forms";
import {Subscriber} from "rxjs";
declare var UIkit;
@Component({
selector: 'quick-contact',
templateUrl: 'quick-contact.component.html',
styleUrls: ['quick-contact.component.css']
})
export class QuickContactComponent implements OnInit, OnDestroy {
public showForm: boolean = false;
@Input()
public contactForm: FormGroup;
@Input()
public sending = false;
@Input()
public organizationTypes: string[] = [];
@Output() sendEmitter: EventEmitter<any> = new EventEmitter<any>();
private subscriptions: any[] = [];
@ViewChild('drop') drop: ElementRef;
ngOnInit() {
if (document !== undefined) {
this.subscriptions.push(UIkit.util.on(document, 'beforehide', '#quick-contact', (event) => {
if(this.sending) {
event.preventDefault();
}
}));
}
}
ngOnDestroy() {
this.subscriptions.forEach(value => {
if (value instanceof Subscriber) {
value.unsubscribe();
} else if (value instanceof Function) {
value();
}
});
}
public close() {
UIkit.drop(this.drop.nativeElement).hide();
}
public send(event) {
this.sendEmitter.emit(event);
}
public toggleModal() {
this.showForm = !this.showForm;
}
}

View File

@ -0,0 +1,23 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {FormsModule} from '@angular/forms';
import {QuickContactComponent} from './quick-contact.component';
import {IconsModule} from '../../utils/icons/icons.module';
import {ContactUsModule} from "../../contact-us/contact-us.module";
import {LoadingModule} from "../../utils/loading/loading.module";
@NgModule({
imports: [
CommonModule, FormsModule, IconsModule, ContactUsModule, LoadingModule
],
declarations: [
QuickContactComponent
],
providers:[],
exports: [
QuickContactComponent
]
})
export class QuickContactModule {
}

View File

@ -0,0 +1,17 @@
import { Injectable } from "@angular/core";
import { BehaviorSubject, Observable } from "rxjs";
@Injectable({
providedIn: "root"
})
export class QuickContactService {
private display: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
public get isDisplayed(): Observable<boolean> {
return this.display.asObservable();
}
public setDisplay(display: boolean) {
this.display.next(display);
}
}

View File

@ -62,7 +62,7 @@ export class Composer {
return email;
}
public static composeEmailForMonitor(contactForm: any, admins: any): Email {
public static composeEmailForMonitor(contactForm: any, admins: string[]): Email {
let email: Email = new Email();
email.subject = "OpenAIRE - Monitor";

View File

@ -7,7 +7,9 @@ import {Observable} from "rxjs";
import {EnvProperties} from "../properties/env-properties";
import {properties} from "../../../../environments/environment";
@Injectable()
@Injectable({
providedIn: 'root'
})
export class EmailService {
constructor(private http:HttpClient) {

View File

@ -153,3 +153,8 @@ export const incognito = {
name: 'incognito',
data: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24.51 19.525"><g id="Group_13376" data-name="Group 13376" transform="translate(-428.81 -3863.018)"><path id="Path_104500" data-name="Path 104500" d="M44.68,105.185H43.024a23.507,23.507,0,0,0-9.194-.158V106a3.909,3.909,0,0,1,1.264,1.668c.455,1.119.2,3.05,4.148,3.289s4-4.041,4.034-4.438.577-.372.577-.372.541-.021.579.372.09,4.673,4.034,4.438,3.693-2.17,4.146-3.289A3.9,3.9,0,0,1,53.879,106v-.969A23.686,23.686,0,0,0,44.68,105.185Z" transform="translate(397.218 3771.582)" fill="#2c2c2c"/><path id="Path_104501" data-name="Path 104501" d="M41.867,35.784H40.326s-1.95-6.217-2.207-6.735a2.8,2.8,0,0,0-2.591-2.061c-1.92-.266-2.138,1.225-3.544,1.268-1.406-.049-1.617-1.546-3.542-1.268a2.817,2.817,0,0,0-2.592,2.061c-.246.518-2.205,6.735-2.205,6.735H22.1a2.31,2.31,0,0,0-2.371,2.245H44.24A2.311,2.311,0,0,0,41.867,35.784Z" transform="translate(409.08 3836.064)" fill="#2c2c2c"/></g></svg>'
}
export const restricted = {
name: 'restricted',
data: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g id="noun-remove-file-3557544" transform="translate(-176.397 -106.4)"><path id="Path_104600" data-name="Path 104600" d="M181.881,274.166A5.485,5.485,0,1,0,178,272.559,5.484,5.484,0,0,0,181.881,274.166Zm-3.548-5.484a3.531,3.531,0,0,1,.452-1.729l4.839,4.839a3.548,3.548,0,0,1-5.29-3.11Zm7.1,0a3.527,3.527,0,0,1-.452,1.729l-4.839-4.839a3.548,3.548,0,0,1,5.29,3.11Z" transform="translate(0 -147.766)" fill="#4b4b4b"/><path id="Path_104601" data-name="Path 104601" d="M245.859,106.4a2.258,2.258,0,0,0-2.258,2.258v4.516h1.936v-4.516a.323.323,0,0,1,.323-.323h8.064v3.871h3.871v11.935a.323.323,0,0,1-.323.323h-5.484V126.4h5.484a2.259,2.259,0,0,0,2.258-2.258v-13.3l-4.439-4.439Z" transform="translate(-63.333)" fill="#4b4b4b"/></g></svg>'
}

View File

@ -0,0 +1,18 @@
declare var UIkit;
export type Status = 'danger' | 'success' | 'warning';
export type Position = 'bottom-right' | 'bottom-left' | 'bottom-center';
export class NotificationHandler {
private static DEFAULT_TIMEOUT: number = 60000;
private static DEFAULT_STATUS: Status = 'success';
private static DEFAULT_POSITION: Position = 'bottom-right';
public static rise(message: string, status: Status = this.DEFAULT_STATUS, position: Position = this.DEFAULT_POSITION) {
UIkit.notification(message, {
status: status,
timeout: this.DEFAULT_TIMEOUT,
pos: position
});
}
}

View File

@ -1,20 +1,3 @@
/*.section {*/
/*position: relative;*/
/*height: auto;*/
/*display: flex;*/
/*}*/
/*.section [top] {*/
/* !*height: 80vh;*!*/
/* !*border: 1px solid rebeccapurple;*!*/
/*}*/
/*.section [top] {*/
/* top: 0;*/
/* height: auto;*/
/* !*border: 1px solid deeppink;*!*/
/*}*/
[left] {
position: -webkit-sticky; /* Safari */
position: sticky;
@ -33,9 +16,13 @@
}
@media (max-width: 960px) {
[left] {
height: 50vh;
}
[left] .imgContainer {
top: 5%;
height: 40%;
height: 80%;
}
[left] > * {
@ -62,4 +49,4 @@
[scroll] > * {
height: 60vh;
/* border: 1px solid darkorange;*/
}
}

View File

@ -67,8 +67,8 @@ export class SectionScrollComponent implements AfterViewInit {
threshold: this.buildThresholdList()
};
Array.from(this.map.values()).forEach(value => {
this.left.set(value, document.getElementById(value));
this.left.get(value).style.display = 'none';
let element = document.getElementById(value);
this.left.set(value, element);
})
Array.from(this.map.keys()).forEach(key => {
this.scroll.set(key, document.getElementById(key));
@ -80,15 +80,8 @@ export class SectionScrollComponent implements AfterViewInit {
if (this.left.has(id) && this.lastElementId !== id) {
if(entry.isIntersecting) {
this.lastElementId = id;
Array.from(this.left.keys()).forEach(element => {
if (element !== id) {
this.left.get(element).style.display = 'none';
} else {
this.left.get(element).style.display = 'block';
}
});
}
// this.left.get(id).parentElement.style.opacity = String(entry.intersectionRatio);
this.left.get(id).parentElement.style.opacity = String(entry.intersectionRatio);
}
});
}, options);

View File

@ -315,6 +315,15 @@ export class StringUtils {
return Validators.pattern(StringUtils.urlRegex);
}
public static validatorType(options: string[]): ValidatorFn {
return (control: AbstractControl): { [key: string]: boolean } | null => {
if (options.filter(type => type === control.value).length === 0) {
return {'type': false};
}
return null;
}
}
public static validRoute(pages: any[], field: string, initial: string = null): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
if(control.value) {

View File

@ -14,23 +14,10 @@ export interface TabIcon {
@Component({
selector: 'my-tab',
// styles: [
// `
// .pane{
// padding: 1em;
// }
// `
// ],
template: `
<!-- [class]="active ? 'uk-active' : ''" [hidden]="!active"-->
<!-- <div [class]="active ? 'uk-active' : ''" [hidden]="!active">-->
<div class="pane">
<div>
<ng-content></ng-content>
</div>
<!-- <div [hidden]="!active" class="pane">-->
<!-- <ng-content></ng-content>-->
<!-- </div>-->
`
})
export class TabComponent {

View File

@ -2,44 +2,29 @@
* The main component that renders single TabComponent
* instances.
*/
import {
Component,
ContentChildren,
QueryList,
AfterContentInit, Output, EventEmitter,
} from '@angular/core';
import { TabComponent } from './tab.component';
import {Component, ContentChildren, EventEmitter, Input, Output, QueryList,} from '@angular/core';
import {TabComponent} from './tab.component';
@Component({
selector: 'my-tabs',
template: `
<ul [class]="(tabs.toArray().length > 2 ? 'uk-visible@m' : '') + ' uk-tab main-tabs uk-margin-remove uk-child-width-expand'"
uk-tab uk-switcher="connect: .tabs-content" uk-height-match="target: .tab-header">
<li *ngFor="let tab of tabs.toArray(); let i=index"
[class]="'uk-padding-remove '+ tab.customClass + (i == 0?' uk-active':'')"
(click)="selectTab(tab)">
<a class="uk-width-1-1 uk-height-1-1" [ngClass]="tab.tabIcon ? 'uk-flex-column' : ''">
<ul class="uk-tab" [ngClass]="customClass" uk-tab="connect: .tabs-content">
<li *ngFor="let tab of tabs.toArray(); let i=index" [ngClass]="tab.customClass" [class.uk-active]="i === 0" (click)="selectTab(tab)">
<a class="uk-width-1-1 uk-height-1-1 uk-flex uk-flex-center" [ngClass]="tab.tabIcon ? 'uk-flex-column' : ''">
<icon *ngIf="tab.tabIcon" [svg]="tab.tabIcon" [fill]="tab.tabIcon" class="uk-margin-small-bottom"></icon>
<div class="tab-header">{{tab.title}}</div>
<div>{{tab.title}}</div>
<div *ngIf="tab.num" class="number">{{tab.num | number}}</div>
<div *ngIf="tab.customClass == 'statistics'" class="number">
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24">
<path d="M0 0h24v24H0z" fill="none"></path>
<path d="M10 20h4V4h-4v16zm-6 0h4v-8H4v8zM16 9v11h4V9h-4z"></path>
</svg>
</div>
</a>
</li>
</ul>
<div [class]="(tabs.toArray().length > 2 ? 'uk-visible@m' : '') + ' uk-switcher tabs-content main-tabs-content'">
<div class="uk-switcher tabs-content">
<ng-content></ng-content>
</div>
`
})
export class TabsComponent {
@Input()
public customClass: string;
@ContentChildren(TabComponent) tabs: QueryList<TabComponent>;
@Output() public selectedActiveTab: EventEmitter<any> = new EventEmitter();