Add slider-components in slider-utils

This commit is contained in:
Konstantinos Triantafyllou 2023-10-05 16:59:41 +03:00
parent 6d7f6eca72
commit cfdd7b2e55
10 changed files with 337 additions and 74 deletions

View File

@ -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');
}
}

View File

@ -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);
}
}

View File

@ -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');
}
}
}

View File

@ -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;
}
}
}

View File

@ -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 {}

View File

@ -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;
}

View File

@ -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 { }

View File

@ -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="">

View File

@ -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;
}

View File

@ -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