Implements Initial Stack Slider
This commit is contained in:
@@ -11,12 +11,14 @@ import { AppServiceWorkerModule } from './app-service-worker.module';
|
||||
import { ServiceWorkerModule } from '@angular/service-worker';
|
||||
import { environment } from '../environments/environment';
|
||||
import { FooterComponent } from './footer/footer.component';
|
||||
import {HomeModule} from "./home/home.module";
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent, HomeComponent, FooterComponent],
|
||||
declarations: [AppComponent, FooterComponent],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
HeaderModule,
|
||||
HomeModule,
|
||||
AppRouterModule,
|
||||
AppServiceWorkerModule,
|
||||
SharedModule,
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
|
||||
background: rgb(46,46,46);
|
||||
background: linear-gradient(180deg, rgba(46,46,46,1) 65%, rgba(46,46,46,0.45) 100%);
|
||||
z-index: 50;
|
||||
|
||||
height: 10vh;
|
||||
|
||||
@@ -97,10 +97,10 @@
|
||||
.stack-section {
|
||||
background: rgb(241,241,241);
|
||||
/*background: linear-gradient(0deg, rgba(241,241,241,1) 80%, rgba(51,51,51,1) 100%);*/
|
||||
height: 90vh;
|
||||
height: 80vh;
|
||||
}
|
||||
.stack {
|
||||
height: 60%;
|
||||
height: 35%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
</div>
|
||||
|
||||
<div class="stack-slider">
|
||||
|
||||
<app-stack-slider>
|
||||
</app-stack-slider>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
21
src/app/home/home.module.ts
Normal file
21
src/app/home/home.module.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import {HomeComponent} from "./home.component";
|
||||
import {StackSliderComponent} from "./stack-slider/stack-slider.component";
|
||||
import {StackCardComponent} from "./stack-slider/stack-card/stack-card.component";
|
||||
import {NgxGlideComponent} from "ngx-glide";
|
||||
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
HomeComponent,
|
||||
StackSliderComponent,
|
||||
StackCardComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
NgxGlideComponent
|
||||
]
|
||||
})
|
||||
export class HomeModule { }
|
||||
@@ -0,0 +1,40 @@
|
||||
.stack-card {
|
||||
width: 300px;
|
||||
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.stack-card-image {
|
||||
width: 100%;
|
||||
border-top-left-radius: 15px !important;
|
||||
border-top-right-radius: 15px !important;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.stack-card-body {
|
||||
padding: 10px;
|
||||
flex-grow: 1;
|
||||
|
||||
width: 250px;
|
||||
height: 130px;
|
||||
inline-size: 250px;
|
||||
}
|
||||
|
||||
.stack-card-text {
|
||||
word-break: break-all !important;
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
|
||||
/*CARD STATE*/
|
||||
.active {
|
||||
opacity: 1;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.inactive {
|
||||
opacity: 0.85;
|
||||
width: 275px;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<div class="card stack-card inactive" [@cardAnimation]="cardState">
|
||||
<img class="card-img-top stack-card-image" [src]="stack.image" alt="Stack Image">
|
||||
<div class="card-body stack-card-body">
|
||||
<h5 class="card-title stack-card-title">{{stack.name}}</h5>
|
||||
<p class="card-text stack-card-text">{{stack.description}}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,21 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { StackCardComponent } from './stack-card.component';
|
||||
|
||||
describe('StackCardComponent', () => {
|
||||
let component: StackCardComponent;
|
||||
let fixture: ComponentFixture<StackCardComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [StackCardComponent]
|
||||
});
|
||||
fixture = TestBed.createComponent(StackCardComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
35
src/app/home/stack-slider/stack-card/stack-card.component.ts
Normal file
35
src/app/home/stack-slider/stack-card/stack-card.component.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {Stack} from "../../../shared/model/stack/stack.model";
|
||||
import {animate, state, style, transition, trigger} from "@angular/animations";
|
||||
|
||||
@Component({
|
||||
selector: 'app-stack-card',
|
||||
templateUrl: './stack-card.component.html',
|
||||
styleUrls: ['./stack-card.component.css'],
|
||||
animations: [
|
||||
trigger('cardAnimation', [
|
||||
state('active', style({
|
||||
opacity: 1,
|
||||
width: '300px',
|
||||
})),
|
||||
state('inactive', style({
|
||||
opacity: 0.85,
|
||||
width: '275px',
|
||||
})),
|
||||
transition('* => *', [
|
||||
animate('0.1s')
|
||||
]),
|
||||
])
|
||||
],
|
||||
})
|
||||
export class StackCardComponent {
|
||||
@Input()
|
||||
stack!: Stack;
|
||||
|
||||
@Input()
|
||||
inFocus: boolean = false;
|
||||
|
||||
get cardState(): 'active'|'inactive' {
|
||||
return this.inFocus ? 'active' : 'inactive';
|
||||
}
|
||||
}
|
||||
5
src/app/home/stack-slider/stack-slider.component.css
Normal file
5
src/app/home/stack-slider/stack-slider.component.css
Normal file
@@ -0,0 +1,5 @@
|
||||
.slider-card {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
9
src/app/home/stack-slider/stack-slider.component.html
Normal file
9
src/app/home/stack-slider/stack-slider.component.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<ng-container class="container" *ngIf="stacks && stacks.length > 0">
|
||||
<ngx-glide #ngxGlide>
|
||||
<ng-container *ngFor="let stack of stacks">
|
||||
<app-stack-card class="slider-card" [stack]="stack"
|
||||
[inFocus]="isInFocus(stack)">
|
||||
</app-stack-card>
|
||||
</ng-container>
|
||||
</ngx-glide>
|
||||
</ng-container>
|
||||
21
src/app/home/stack-slider/stack-slider.component.spec.ts
Normal file
21
src/app/home/stack-slider/stack-slider.component.spec.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { StackSliderComponent } from './stack-slider.component';
|
||||
|
||||
describe('StackSliderComponent', () => {
|
||||
let component: StackSliderComponent;
|
||||
let fixture: ComponentFixture<StackSliderComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [StackSliderComponent]
|
||||
});
|
||||
fixture = TestBed.createComponent(StackSliderComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
76
src/app/home/stack-slider/stack-slider.component.ts
Normal file
76
src/app/home/stack-slider/stack-slider.component.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import {AfterViewInit, ChangeDetectorRef, Component, ViewChild} from '@angular/core';
|
||||
import {NgxGlideComponent} from "ngx-glide";
|
||||
import {Stack} from "../../shared/model/stack/stack.model";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-stack-slider',
|
||||
templateUrl: './stack-slider.component.html',
|
||||
styleUrls: ['./stack-slider.component.css']
|
||||
})
|
||||
export class StackSliderComponent implements AfterViewInit {
|
||||
@ViewChild('ngxGlide')
|
||||
ngxGlide!: NgxGlideComponent;
|
||||
|
||||
stacks: Stack[] = [
|
||||
{
|
||||
name: 'Angular',
|
||||
image: 'https://picsum.photos/id/1/100/100',
|
||||
description: 'Angular is a platform for building mobile and desktop web applications.',
|
||||
},
|
||||
{
|
||||
name: 'React',
|
||||
image: 'https://picsum.photos/id/2/100/100',
|
||||
description: 'React is a JavaScript library for building user interfaces.',
|
||||
},
|
||||
{
|
||||
name: 'Vue',
|
||||
image: 'https://picsum.photos/id/3/100/100',
|
||||
description: 'Vue is a progressive framework for building user interfaces.',
|
||||
},
|
||||
{
|
||||
name: 'Svelte',
|
||||
image: 'https://picsum.photos/id/4/100/100',
|
||||
description: 'Svelte is a radical new approach to building user interfaces.',
|
||||
},
|
||||
{
|
||||
name: 'Ember',
|
||||
image: 'https://picsum.photos/id/5/100/100',
|
||||
description: 'Ember.js is an open-source JavaScript web framework.',
|
||||
},
|
||||
{
|
||||
name: 'Preact',
|
||||
image: 'https://picsum.photos/id/6/100/100',
|
||||
description: 'Preact is a fast 3kB alternative to React with the same modern API.',
|
||||
}
|
||||
]
|
||||
|
||||
constructor(private cd: ChangeDetectorRef) { }
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
if (this.ngxGlide)
|
||||
this.buildCarousel();
|
||||
|
||||
this.cd.detectChanges();
|
||||
}
|
||||
|
||||
buildCarousel(): void {
|
||||
this.ngxGlide.showArrows = false;
|
||||
this.ngxGlide.showBullets = false;
|
||||
this.ngxGlide.type = 'carousel';
|
||||
this.ngxGlide.perView = 5;
|
||||
this.ngxGlide.focusAt = 'center';
|
||||
this.ngxGlide.gap = 10;
|
||||
this.ngxGlide.autoplay = 3000;
|
||||
|
||||
this.ngxGlide.recreate();
|
||||
}
|
||||
|
||||
get currentIndex(): number {
|
||||
return this.ngxGlide?.getIndex();
|
||||
}
|
||||
|
||||
isInFocus(stack: Stack): boolean {
|
||||
return this.stacks.indexOf(stack) === this.currentIndex;
|
||||
}
|
||||
}
|
||||
5
src/app/shared/model/stack/stack.model.ts
Normal file
5
src/app/shared/model/stack/stack.model.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface Stack {
|
||||
name: string;
|
||||
image: string;
|
||||
description: string;
|
||||
}
|
||||
Reference in New Issue
Block a user