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 {SliderArrowComponent} from "./slider-arrow.component";
|
||||
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({
|
||||
imports: [CommonModule, IconsModule],
|
||||
declarations: [SliderArrowComponent],
|
||||
exports: [SliderArrowComponent]
|
||||
imports: [CommonModule, IconsModule, RouterLink],
|
||||
declarations: [SliderContainerComponent, SliderArrowComponent, SliderNavItemComponent, SliderItemComponent, SliderColumnComponent],
|
||||
exports: [SliderContainerComponent, SliderArrowComponent, SliderNavItemComponent, SliderItemComponent, SliderColumnComponent],
|
||||
})
|
||||
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>
|
||||
<div class="uk-section uk-section-default">
|
||||
<div class="uk-container">
|
||||
|
||||
<div uk-grid="" class="uk-grid">
|
||||
<div class="uk-width-2-3@m uk-first-column">
|
||||
|
||||
|
@ -292,10 +291,10 @@
|
|||
|
||||
<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-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>
|
||||
|
||||
<div class="uk-width-1-2">
|
||||
|
@ -468,6 +467,41 @@
|
|||
</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">
|
||||
|
||||
<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 {ActivatedRoute} from "@angular/router";
|
||||
import {Subscriber} from "rxjs";
|
||||
import {OpenaireEntities} from "../properties/searchFields";
|
||||
|
||||
|
||||
@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 {IconsModule} from "../icons/icons.module";
|
||||
import {InputModule} from "../../sharedComponents/input/input.module";
|
||||
import {SliderUtilsModule} from "../../sharedComponents/slider-utils/slider-utils.module";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule, RouterModule,
|
||||
ThemeRoutingModule, IconsModule, InputModule
|
||||
ThemeRoutingModule, IconsModule, InputModule, SliderUtilsModule
|
||||
],
|
||||
declarations: [
|
||||
ThemeComponent
|
||||
|
|
Loading…
Reference in New Issue