Production release November 2023 #20
|
@ -0,0 +1,78 @@
|
||||||
|
import {AfterContentInit, Component, ContentChildren, Input, OnDestroy, QueryList} from '@angular/core';
|
||||||
|
import {SliderItemComponent} from "./slider-item.component";
|
||||||
|
import {SliderNavItemComponent} from "./slider-nav-item.component";
|
||||||
|
import {SliderContainerComponent} from "./slider-container.component";
|
||||||
|
import {LayoutService} from "../../dashboard/sharedComponents/sidebar/layout.service";
|
||||||
|
import {Subscriber} from "rxjs";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'slider-column',
|
||||||
|
template: `
|
||||||
|
<div class="uk-position-relative">
|
||||||
|
<ng-content></ng-content>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export class SliderColumnComponent implements AfterContentInit, OnDestroy {
|
||||||
|
@Input()
|
||||||
|
type: 'slider' | 'nav' = null;
|
||||||
|
@Input()
|
||||||
|
animation = 'uk-animation-fade';
|
||||||
|
@ContentChildren(SliderItemComponent) items: QueryList<SliderItemComponent>;
|
||||||
|
@ContentChildren(SliderNavItemComponent) navItems: QueryList<SliderNavItemComponent>;
|
||||||
|
public isMobile: boolean;
|
||||||
|
private subscriptions: any[] = [];
|
||||||
|
|
||||||
|
constructor(private layoutService: LayoutService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.subscriptions.forEach(value => {
|
||||||
|
if (value instanceof Subscriber) {
|
||||||
|
value.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterContentInit() {
|
||||||
|
this.slides.forEach(slide => {
|
||||||
|
slide.init(this.animation);
|
||||||
|
});
|
||||||
|
this.navItems.forEach(slide => {
|
||||||
|
slide.init(this.animation);
|
||||||
|
});
|
||||||
|
this.subscriptions.push(this.layoutService.isMobile.subscribe(isMobile => {
|
||||||
|
this.isMobile = isMobile;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
change(time: number) {
|
||||||
|
if (this.type === 'slider') {
|
||||||
|
let slides = this.slides;
|
||||||
|
for (let i = 0; i < slides.length; i++) {
|
||||||
|
slides[i].setActive(slides[i].start <= time && (!slides[i + 1] || slides[i + 1].start > time));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.type === 'nav') {
|
||||||
|
let slides = this.navItems;
|
||||||
|
for (let i = 0; i < slides.length; i++) {
|
||||||
|
if (this.isMobile) {
|
||||||
|
slides.get(i).setActive(slides.get(i).start <= time && (!slides.get(i + 1) || slides.get(i + 1).start > time));
|
||||||
|
}
|
||||||
|
slides.get(i).active = slides.get(i).start <= time && (!slides.get(i + 1) || slides.get(i + 1).start > time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setContainer(container: SliderContainerComponent) {
|
||||||
|
if (this.type === 'nav') {
|
||||||
|
this.navItems.forEach(item => {
|
||||||
|
item.container = container;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get slides(): SliderItemComponent[] {
|
||||||
|
return this.items.filter(item => item.type === 'slide');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
import {
|
||||||
|
AfterContentInit,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
Component,
|
||||||
|
ContentChildren,
|
||||||
|
ElementRef,
|
||||||
|
Input, OnDestroy,
|
||||||
|
OnInit,
|
||||||
|
QueryList
|
||||||
|
} from "@angular/core";
|
||||||
|
import {SliderColumnComponent} from "./slider-column.component";
|
||||||
|
|
||||||
|
export class Stage {
|
||||||
|
value: number;
|
||||||
|
max: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'slider-container',
|
||||||
|
template: `
|
||||||
|
<div class="uk-grid uk-grid-large uk-flex uk-flex-middle uk-child-width-1-1" [ngClass]="'uk-child-width-1-' + sliders?.length + '@m'" uk-grid>
|
||||||
|
<ng-content></ng-content>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="navigation === 'progress' && stages.length > 0" class="uk-flex uk-flex-center uk-margin-large-top">
|
||||||
|
<div class="uk-width-1-3@m uk-width-1-1 uk-grid uk-grid-small uk-flex-middle" [ngClass]="'uk-child-width-1-' + stages.length" uk-grid>
|
||||||
|
<div *ngFor="let stage of stages; let i=index">
|
||||||
|
<progress (click)="start(i)" class="uk-progress" [value]="stage.value" [max]="stage.max"></progress>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export class SliderContainerComponent implements OnInit, OnDestroy, AfterContentInit {
|
||||||
|
private static INTERVAL = 10;
|
||||||
|
private static ANIMATION_DURATION = 600; // UIKit progress animation duration
|
||||||
|
|
||||||
|
@ContentChildren(SliderColumnComponent) sliders: QueryList<SliderColumnComponent>;
|
||||||
|
@Input()
|
||||||
|
navigation: 'progress' | null = null;
|
||||||
|
@Input()
|
||||||
|
total: number = 0;
|
||||||
|
@Input()
|
||||||
|
period: number = 3000; // in ms (>= 1000ms)
|
||||||
|
@Input()
|
||||||
|
infinite: boolean = false;
|
||||||
|
@Input()
|
||||||
|
parent: HTMLDivElement;
|
||||||
|
stages: Stage[] = [];
|
||||||
|
time: number = 0;
|
||||||
|
interval: any;
|
||||||
|
observer: IntersectionObserver;
|
||||||
|
initialized: boolean = false;
|
||||||
|
stopped: boolean = true;
|
||||||
|
|
||||||
|
constructor(private cdr: ChangeDetectorRef, private element: ElementRef) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.period = this.period - SliderContainerComponent.ANIMATION_DURATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
if(this.observer) {
|
||||||
|
this.observer.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterContentInit() {
|
||||||
|
this.setObserver();
|
||||||
|
this.sliders.forEach(slider => {
|
||||||
|
slider.setContainer(this);
|
||||||
|
slider.navItems.forEach(item => {
|
||||||
|
if(this.parent) {
|
||||||
|
item.background = getComputedStyle(this.parent).backgroundColor;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setObserver() {
|
||||||
|
let options = {
|
||||||
|
root: null,
|
||||||
|
rootMargin: '0px',
|
||||||
|
threshold: 0.1
|
||||||
|
};
|
||||||
|
this.observer = new IntersectionObserver(entries => {
|
||||||
|
entries.forEach(entry => {
|
||||||
|
if (entry.isIntersecting && !this.initialized) {
|
||||||
|
this.stopped = false;
|
||||||
|
this.start(0);
|
||||||
|
this.initialized = true;
|
||||||
|
} else {
|
||||||
|
this.initialized = false;
|
||||||
|
this.stopped = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, options);
|
||||||
|
this.observer.observe(this.element.nativeElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
start(time: number) {
|
||||||
|
this.stages = [];
|
||||||
|
for(let i = 0; i < this.total; i++) {
|
||||||
|
this.stages.push({value: (time > i?this.period:(time - i)), max: this.period});
|
||||||
|
}
|
||||||
|
if(this.interval) {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
}
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
this.interval = setInterval(() => {
|
||||||
|
let current = Math.floor(time);
|
||||||
|
this.stages[current].value += SliderContainerComponent.INTERVAL;
|
||||||
|
this.time = current + this.stages[current].value/this.stages[current].max;
|
||||||
|
this.sliders.forEach(slider => {
|
||||||
|
slider.change(this.time);
|
||||||
|
});
|
||||||
|
if(this.stages[current].value >= this.stages[current].max) {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
let next = (current + 1 > this.total - 1)?0:current + 1;
|
||||||
|
if(!this.stopped && (this.infinite || next > current)) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.start(next);
|
||||||
|
}, SliderContainerComponent.ANIMATION_DURATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, SliderContainerComponent.INTERVAL);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
import {Component, ElementRef, Input} from "@angular/core";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'slider-item',
|
||||||
|
template: `
|
||||||
|
<ng-content></ng-content>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export class SliderItemComponent {
|
||||||
|
@Input()
|
||||||
|
type: 'slide' | 'static' = 'slide';
|
||||||
|
@Input()
|
||||||
|
start: number;
|
||||||
|
|
||||||
|
constructor(private element: ElementRef) {
|
||||||
|
}
|
||||||
|
|
||||||
|
init(animation: string) {
|
||||||
|
this.element.nativeElement.classList.add(animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
setActive(active: boolean) {
|
||||||
|
if(active) {
|
||||||
|
this.element.nativeElement.classList.remove('uk-hidden');
|
||||||
|
} else {
|
||||||
|
this.element.nativeElement.classList.add('uk-hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
import {AfterViewInit, Component, ElementRef, Input, ViewChild} from "@angular/core";
|
||||||
|
import {ActivatedRoute} from "@angular/router";
|
||||||
|
import {SliderContainerComponent} from "./slider-container.component";
|
||||||
|
import {SliderItemComponent} from "./slider-item.component";
|
||||||
|
|
||||||
|
export interface Link {
|
||||||
|
routerLink?: {
|
||||||
|
commands: string[] | string,
|
||||||
|
queryParams?: Object,
|
||||||
|
fragment?: string,
|
||||||
|
relativeTo?: ActivatedRoute
|
||||||
|
}
|
||||||
|
href?: string
|
||||||
|
external?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'slider-nav-item',
|
||||||
|
template: `
|
||||||
|
<div *ngIf="container" (click)="container.start(start)" class="uk-flex uk-flex-middle" [class.uk-active]="active">
|
||||||
|
<div class="uk-width-expand">
|
||||||
|
<ng-content></ng-content>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="link" class="action">
|
||||||
|
<a *ngIf="link?.routerLink" #linkElement class="uk-text-decoration-none" [routerLink]="link.routerLink.commands" [queryParams]="link.routerLink.queryParams"
|
||||||
|
[fragment]="link.routerLink.fragment" [relativeTo]="link.routerLink.relativeTo" [target]="link.external?'_blank':'_self'">
|
||||||
|
<icon name="chevron_right" ratio="1.5" [flex]="true"></icon>
|
||||||
|
</a>
|
||||||
|
<a *ngIf="link?.href" #linkElement [href]="link.href" class="uk-text-decoration-none" [target]="link.external?'_blank':'_self'">
|
||||||
|
<icon name="chevron_right" ratio="1.5" [flex]="true"></icon>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export class SliderNavItemComponent extends SliderItemComponent implements AfterViewInit {
|
||||||
|
@Input()
|
||||||
|
link: Link = null;
|
||||||
|
@Input()
|
||||||
|
start: number;
|
||||||
|
active: boolean = false;
|
||||||
|
container: SliderContainerComponent;
|
||||||
|
background: string;
|
||||||
|
@ViewChild('linkElement') linkElement: ElementRef;
|
||||||
|
|
||||||
|
ngAfterViewInit() {
|
||||||
|
if(this.linkElement) {
|
||||||
|
this.linkElement.nativeElement.style.background = this.background;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,10 +2,15 @@ import {NgModule} from "@angular/core";
|
||||||
import {CommonModule} from "@angular/common";
|
import {CommonModule} from "@angular/common";
|
||||||
import {SliderArrowComponent} from "./slider-arrow.component";
|
import {SliderArrowComponent} from "./slider-arrow.component";
|
||||||
import {IconsModule} from "../../utils/icons/icons.module";
|
import {IconsModule} from "../../utils/icons/icons.module";
|
||||||
|
import {SliderNavItemComponent} from "./slider-nav-item.component";
|
||||||
|
import {SliderItemComponent} from "./slider-item.component";
|
||||||
|
import {RouterLink} from "@angular/router";
|
||||||
|
import {SliderColumnComponent} from "./slider-column.component";
|
||||||
|
import {SliderContainerComponent} from "./slider-container.component";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [CommonModule, IconsModule],
|
imports: [CommonModule, IconsModule, RouterLink],
|
||||||
declarations: [SliderArrowComponent],
|
declarations: [SliderContainerComponent, SliderArrowComponent, SliderNavItemComponent, SliderItemComponent, SliderColumnComponent],
|
||||||
exports: [SliderArrowComponent]
|
exports: [SliderContainerComponent, SliderArrowComponent, SliderNavItemComponent, SliderItemComponent, SliderColumnComponent],
|
||||||
})
|
})
|
||||||
export class SliderUtilsModule {}
|
export class SliderUtilsModule {}
|
|
@ -1,47 +0,0 @@
|
||||||
import {Component, Input} from '@angular/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'gif-slider',
|
|
||||||
template: `
|
|
||||||
<div tabindex="-1" [attr.uk-slider]="'velocity: ' + velocity +
|
|
||||||
';autoplay: '+ autoplay +
|
|
||||||
';autoplay-interval: ' + autoplayInterval +
|
|
||||||
';pause-on-hover: ' + pauseOnHover +
|
|
||||||
';center: ' + center">
|
|
||||||
<div class="uk-slider-container">
|
|
||||||
<ul class="uk-slider-items uk-child-width-1-1">
|
|
||||||
<li *ngFor="let gif of gifs">
|
|
||||||
<div class="uk-flex uk-padding uk-child-width-1-2@m uk-child-width-1-1@s" uk-grid>
|
|
||||||
<div>
|
|
||||||
<img [attr.src]="gif.gif" class="uk-box-shadow-large uk-border-rounded" loading="lazy">
|
|
||||||
</div>
|
|
||||||
<div [ngClass]="(gifRight)?'uk-flex-first':''" class="uk-margin-top">
|
|
||||||
<div>
|
|
||||||
<div class="uk-text-bold uk-h4">{{gif.header}}</div>
|
|
||||||
<div class="uk-margin-medium"> {{gif.text}}</div>
|
|
||||||
<div *ngIf="link" class="uk-inline">
|
|
||||||
<a class="uk-button portal-button uk-text-uppercase" [routerLink]="route" routerLinkActive="router-link-active">{{linkTitle}}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<ul class="uk-slider-nav uk-dotnav uk-flex-center uk-margin"></ul>
|
|
||||||
</div>
|
|
||||||
</div>`
|
|
||||||
})
|
|
||||||
|
|
||||||
export class GifSliderComponent {
|
|
||||||
@Input() gifs: {"gif": string, "header": string, "text"}[] = [];
|
|
||||||
@Input() link = false;
|
|
||||||
@Input() route = null;
|
|
||||||
@Input() linkTitle = null;
|
|
||||||
@Input() gifRight = false;
|
|
||||||
@Input() velocity = 0;
|
|
||||||
@Input() autoplay = true;
|
|
||||||
@Input() autoplayInterval = 4000;
|
|
||||||
@Input() pauseOnHover = false;
|
|
||||||
@Input() center = true;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
import { NgModule} from '@angular/core';
|
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { RouterModule } from '@angular/router';
|
|
||||||
import {GifSliderComponent} from "./gif-slider.component";
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [
|
|
||||||
CommonModule, RouterModule
|
|
||||||
],
|
|
||||||
declarations: [
|
|
||||||
GifSliderComponent
|
|
||||||
],
|
|
||||||
providers:[
|
|
||||||
],
|
|
||||||
exports: [
|
|
||||||
GifSliderComponent
|
|
||||||
]
|
|
||||||
})
|
|
||||||
export class GifSliderModule { }
|
|
|
@ -44,7 +44,6 @@
|
||||||
</nav>
|
</nav>
|
||||||
<div class="uk-section uk-section-default">
|
<div class="uk-section uk-section-default">
|
||||||
<div class="uk-container">
|
<div class="uk-container">
|
||||||
|
|
||||||
<div uk-grid="" class="uk-grid">
|
<div uk-grid="" class="uk-grid">
|
||||||
<div class="uk-width-2-3@m uk-first-column">
|
<div class="uk-width-2-3@m uk-first-column">
|
||||||
|
|
||||||
|
@ -292,10 +291,10 @@
|
||||||
|
|
||||||
<hr class="uk-margin-large">
|
<hr class="uk-margin-large">
|
||||||
|
|
||||||
<div id="inputs" class="uk-grid-divider uk-grid" uk-grid="">
|
<div class="uk-grid-divider uk-grid" uk-grid="">
|
||||||
<div class="uk-width-3-5@m uk-first-column">
|
<div class="uk-width-3-5@m uk-first-column">
|
||||||
|
|
||||||
<div class="uk-child-width-expand@s uk-grid" uk-grid="">
|
<div id="inputs" class="uk-child-width-expand@s uk-grid" uk-grid="">
|
||||||
<form class="uk-grid uk-child-width-1-1" uk-grid>
|
<form class="uk-grid uk-child-width-1-1" uk-grid>
|
||||||
|
|
||||||
<div class="uk-width-1-2">
|
<div class="uk-width-1-2">
|
||||||
|
@ -468,6 +467,41 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="sliders" #sliders class="uk-section uk-section-default">
|
||||||
|
<slider-container [total]="3" [navigation]="'progress'" [parent]="sliders">
|
||||||
|
<slider-column type="slider">
|
||||||
|
<slider-item type="slide" [start]="0">
|
||||||
|
<img src="assets/common-assets/logo-services/connect/main.svg" alt="ipad" loading="lazy">
|
||||||
|
</slider-item>
|
||||||
|
<slider-item type="slide" [start]="1">
|
||||||
|
<img src="assets/common-assets/logo-services/explore/main.svg" alt="ipad" loading="lazy">
|
||||||
|
</slider-item>
|
||||||
|
<slider-item type="slide" [start]="2">
|
||||||
|
<img src="assets/common-assets/logo-services/monitor/main.svg" alt="ipad" loading="lazy">
|
||||||
|
</slider-item>
|
||||||
|
</slider-column>
|
||||||
|
<slider-column type="nav">
|
||||||
|
<slider-nav-item [start]="0" [link]="{href: 'http://mpagasas.di.uoa.gr:4200'}">
|
||||||
|
<h3 class="uk-h6">
|
||||||
|
OpenAIRE Connect
|
||||||
|
</h3>
|
||||||
|
</slider-nav-item>
|
||||||
|
<slider-nav-item [start]="1">
|
||||||
|
<h3 class="uk-h6">
|
||||||
|
OpenAIRE Explore
|
||||||
|
</h3>
|
||||||
|
</slider-nav-item>
|
||||||
|
<slider-nav-item [start]="2">
|
||||||
|
<h3 class="uk-h6">
|
||||||
|
OpenAIRE Monitor
|
||||||
|
</h3>
|
||||||
|
</slider-nav-item>
|
||||||
|
</slider-column>
|
||||||
|
</slider-container>
|
||||||
|
</div>
|
||||||
|
|
||||||
<hr class="uk-margin-medium">
|
<hr class="uk-margin-medium">
|
||||||
|
|
||||||
<div class="uk-child-width-1-2@s uk-child-width-expand@m uk-grid" uk-grid="">
|
<div class="uk-child-width-1-2@s uk-child-width-expand@m uk-grid" uk-grid="">
|
||||||
|
|
|
@ -3,6 +3,7 @@ import {ValidatorFn, Validators} from "@angular/forms";
|
||||||
import {StringUtils} from "../string-utils.class";
|
import {StringUtils} from "../string-utils.class";
|
||||||
import {ActivatedRoute} from "@angular/router";
|
import {ActivatedRoute} from "@angular/router";
|
||||||
import {Subscriber} from "rxjs";
|
import {Subscriber} from "rxjs";
|
||||||
|
import {OpenaireEntities} from "../properties/searchFields";
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -36,4 +37,6 @@ export class ThemeComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected readonly OpenaireEntities = OpenaireEntities;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,12 @@ import {ThemeRoutingModule} from "./theme-routing.module";
|
||||||
import {ThemeComponent} from "./theme.component";
|
import {ThemeComponent} from "./theme.component";
|
||||||
import {IconsModule} from "../icons/icons.module";
|
import {IconsModule} from "../icons/icons.module";
|
||||||
import {InputModule} from "../../sharedComponents/input/input.module";
|
import {InputModule} from "../../sharedComponents/input/input.module";
|
||||||
|
import {SliderUtilsModule} from "../../sharedComponents/slider-utils/slider-utils.module";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule, RouterModule,
|
CommonModule, RouterModule,
|
||||||
ThemeRoutingModule, IconsModule, InputModule
|
ThemeRoutingModule, IconsModule, InputModule, SliderUtilsModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
ThemeComponent
|
ThemeComponent
|
||||||
|
|
Loading…
Reference in New Issue