app/dxa/dxa-entity/views/related-link-views/related-links-sequence-main/related-links-sequence-main.component.ts
selector | div[related-links-sequence] |
styleUrls | ./related-links-sequence-main.component.scss |
templateUrl | ./related-links-sequence-main.component.html |
Properties |
Methods |
Inputs |
HostBindings |
constructor(doc, constants: ConstantsService, util: UtilService, linkService: ComponentLinkService, activatedRoute: ActivatedRoute)
|
||||||||||||||||||
Parameters :
|
entity | |
class |
getDirectionClass | ||||||
getDirectionClass(index, rowNumber)
|
||||||
Get class for direction of arrow
Parameters :
Returns :
string
|
getOrder | ||||
getOrder(index)
|
||||
Get the position of a component based on its index. Used to switch placement in mobile view
Parameters :
Returns :
string
|
inDesktopView |
inDesktopView()
|
Check if on desktop screen width
Returns :
boolean
|
inMobileView |
inMobileView()
|
Check if on mobile screen width
Returns :
boolean
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
Private resolveSequence | ||||
resolveSequence(sequence)
|
||||
Parameters :
Returns :
RelatedSequence
|
sequences |
Type : []
|
Default value : []
|
import { Component, Input, OnInit, Inject, HostBinding } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { ConstantsService } from 'src/app/shared/constants/constants.service';
import { UtilService } from 'src/app/core/services/util-service/util.service';
import { ComponentLinkService } from 'src/app/core/services/component-link-service/component-link.service';
import { Router, ActivatedRoute } from '@angular/router';
interface RelatedSequence {
title: string;
icon: string;
linkObject: any;
linkTitle: string;
readMoreTitle: string;
active: boolean;
}
@Component({
selector: 'div[related-links-sequence]',
templateUrl: './related-links-sequence-main.component.html',
styleUrls: ['./related-links-sequence-main.component.scss']
})
export class RelatedLinksSequenceMainComponent implements OnInit {
@Input() entity;
sequences = [];
@HostBinding('class') get class() { return 'col-md-12 space-between'; }
constructor(
@Inject(DOCUMENT) private doc,
private constants: ConstantsService,
private util: UtilService,
private linkService: ComponentLinkService,
private activatedRoute: ActivatedRoute
) { }
ngOnInit(): void {
const entities = this.util.extract(this.entity, 'Entities');
this.sequences = (entities ? entities : []).map(seq => this.resolveSequence(seq));
}
/** Get the position of a component based on its index. Used to switch placement in mobile view */
getOrder(index): string {
let classString = '';
// No classes on desktop view
if (this.inDesktopView()) {
return classString;
}
if (index <= 1) { // Regular order for first 2 elements
const direction = this.getDirectionClass(index, 0);
classString = `order-${index} ${direction}`;
} else {
const rowNumber = Math.floor(index / 2);
const direction = this.getDirectionClass(index, rowNumber);
const evenIndex = index % 2 === 0;
const evenRow = rowNumber % 2 === 0;
const oddAmountOfLinks = this.sequences.length % 2 !== 0;
/** Flip order of elements on odd rows
* Even index + odd row number -> increase order by 1
* Odd index + odd row number -> decrease order by 1
*/
if (index > 1 && evenIndex && !evenRow) {
classString = `order-${index + 1} ${direction}`;
} else if (index > 1 && !evenIndex && !evenRow) {
classString = `order-${index - 1} ${direction}`;
} else {
classString = `order-${index} ${direction}`;
}
// Set last item to 100% width if there are odd number of links
if (index === this.sequences.length - 1 && oddAmountOfLinks) {
classString += ' w-100';
}
}
return classString;
}
/** Get class for direction of arrow */
getDirectionClass(index, rowNumber): string {
// Last item should have no arrow
if (index === this.sequences.length - 1) { return ''; }
const evenIndex = index % 2 === 0;
const evenRow = rowNumber % 2 === 0;
/**
* Even index + even row number -> right arrow.
* Even index + odd row number -> left arrow.
* Odd index + even row number -> right down arrow
* Odd index + odd row number -> left down arrow
*/
if (evenIndex) {
return evenRow ? 'right-arrow' : 'left-arrow';
} else {
return evenRow ? 'right-down-arrow' : 'left-down-arrow';
}
}
private resolveSequence(sequence): RelatedSequence {
const linkObject = this.util.extract(sequence, 'LinkTargets', [0]);
const linkUrl = this.linkService.getUrl(linkObject);
return {
title: this.util.extract(sequence, 'Title'),
icon: this.util.extract(sequence, 'Icon'),
linkObject: linkObject,
linkTitle: this.linkService.getTitle(linkObject),
readMoreTitle: this.util.extract(sequence, 'ReadMoreLinkTitle'),
active: linkUrl === `/${this.activatedRoute.snapshot.url.join('/')}`
};
}
/** Check if on desktop screen width */
inDesktopView(): boolean {
return (window.innerWidth || this.doc.documentElement.clientWidth) > this.constants.BOOTSTRAP_BREAKPOINTS.LG;
}
/** Check if on mobile screen width */
inMobileView(): boolean {
return (window.innerWidth || this.doc.documentElement.clientWidth) < this.constants.BOOTSTRAP_BREAKPOINTS.MD;
}
}
<div class="related-sequence">
<h5 class="mb-4 title" *ngIf="sequences[0].readMoreTitle">{{sequences[0].readMoreTitle | uppercase }}</h5>
<div class="card-group">
<a component-link [ngClass]="['card', getOrder(i), sequence.active ? 'active' : '']" [linkObject]="sequence.linkObject" [ngStyle]="{'z-index': sequences.length - i}" *ngFor="let sequence of sequences; let i=index">
<div class="card-body">
<i *ngIf="!inMobileView() && sequence.icon" [class]="sequence.icon"></i>
<div>
<div class="card-title">
<i *ngIf="inMobileView()" [ngClass]="[sequence.icon ? sequence.icon : '', 'link-icon' ]"></i>
<span>{{sequence.title | uppercase}}</span>
<i class="icon-chevronLarge-next chevron" *ngIf="!sequence.active"></i>
</div>
<div class="card-text">
<i *ngIf="sequence.linkObject?.LinkModelTarget?.MimeType === 'application/zip' " class="icon-link-download"></i>
{{sequence.linkTitle}}
</div>
</div>
</div>
</a>
</div>
</div>
./related-links-sequence-main.component.scss
@import "src/app/styles/helpers";
.related-sequence {
padding: calc-rem(30) 0;
.title {
@include font-scale(14, uppercase);
}
.card-group {
>.card {
flex: unset;
@include media-breakpoint-up(lg) {
flex: 1 0 0%;
}
}
@include media-breakpoint-down(lg) {
flex-direction: row;
flex-wrap: wrap;
}
}
.card {
width: 50%;
margin-bottom: 0;
border: none; // remove default card border
position: relative;
background: $cool-grey;
border: 2px solid white;
&[target=_blank]:after {
content: none;
margin: 0;
}
&.active {
background: $dark-blue;
}
&-body {
padding-left: calc-rem(25);
@include media-breakpoint-down(md) {
display: flex;
}
i {
align-self: center;
color: $light-blue;
@include font-size(25);
@include media-breakpoint-up(sm) { margin-right: calc-rem(10); }
}
}
&-title {
display: flex;
align-items: center;
margin-bottom: 0;
color: $light-blue;
@include font-size(14);
.link-icon {
@include font-size(20);
margin-right: calc-rem(5);
}
.chevron {
@include font-size(13);
}
}
&-text {
color: white;
@include font-size(14);
.icon-link-download {
@include font-size(14);
margin-right: calc-rem(5);
}
}
&:not(:last-child) {
&:after, &:before {
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
&:after {
border-color: rgba(72, 90, 100, 0); // White color for arrow
border-width: calc-rem(16);
}
&:before {
border-color: rgba(194, 225, 245, 0); // White color for arrow
border-width: calc-rem(22);
}
}
&.right-arrow {
&:after, &:before {
left: 100%;
top: 50%;
}
&:after {
border-left-color: $cool-grey;
margin-top: calc-rem(-14);
}
&:before {
border-left-color: white;
margin-top: calc-rem(-20);
}
&:hover {
&:after {
border-left-color: $blue;
}
}
&.active {
&:after {
border-left-color: $dark-blue;
}
&:hover {
&:after { border-left-color: $blue; }
}
}
}
&.left-arrow {
&:after, &:before {
right: 100%;
top: 50%;
}
&:after {
border-right-color: $cool-grey;
margin-top: calc-rem(-14);
}
&:before {
border-right-color: white;
margin-top: calc-rem(-20);
}
&:hover {
&:after {
border-right-color: $blue;
}
}
&.active {
&:after {
border-right-color: $dark-blue;
}
&:hover {
&:after { border-right-color: $blue; }
}
}
}
&.right-down-arrow {
&:after, &:before {
top: 100%;
right: 20%;
}
&:after {
border-top-color: $cool-grey;
margin-right: calc-rem(-14);
}
&:before {
border-top-color: white;
margin-right: calc-rem(-20);
}
&:hover {
&:after {
border-top-color: $blue;
}
}
&.active {
&:after {
border-top-color: $dark-blue;
}
&:hover {
&:after {
border-top-color: $blue;
}
}
}
}
&.left-down-arrow {
&:after, &:before {
top: 100%;
left: 20%;
}
&:after {
border-top-color: $cool-grey;
margin-left: calc-rem(-14);
}
&:before {
border-top-color: white;
margin-left: calc-rem(-20);
}
&:hover {
&:after {
border-top-color: $blue;
}
}
&.active {
&:after {
border-top-color: $dark-blue;
}
&:hover {
&:after {
border-top-color: $blue;
}
}
}
}
// Desktop view
@include media-breakpoint-up(lg) {
width: calc(12.5% - calc-rem(10));
&:not(:last-child) {
&:after, &:before {
right: unset;
left: 100%;
top: 50%;
}
&:after {
// Reset style from mobile view
border-color: unset;
margin: 0;
border-color: rgba(72, 90, 100, 0); // White color for arrow
border-left-color: $cool-grey;
margin-top: calc-rem(-14);
}
&:before {
// Reset style from mobile view
border-color: unset;
margin: 0;
border-color: rgba(72, 90, 100, 0); // White color for arrow
border-left-color: white;
margin-top: calc-rem(-20);
}
&.active {
&:after {
border-left-color: $dark-blue;
}
&:hover {
&:after {
border-left-color: $blue;
}
}
}
}
&:hover {
&:after { border-left-color: $blue; }
}
}
&:hover {
background: $blue;
text-decoration: none;
}
}
}