UNPKG

mt-portfolio

Version:

A Portfolio maker for Angular with image, heading, caption, ability to add contact form and demo

358 lines (347 loc) 19.9 kB
import { animation, style, animate, keyframes, trigger, transition, useAnimation } from '@angular/animations'; import * as i0 from '@angular/core'; import { Pipe, Component, Input, EventEmitter, Directive, Output, HostListener, NgModule } from '@angular/core'; import * as i1 from '@angular/platform-browser'; import * as i1$1 from '@angular/common'; import { CommonModule } from '@angular/common'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; class PortfolioModel { constructor() { this.src = ''; this.srcLarge = ''; this.srcMedium = ''; this.alt = ''; this.x = ''; this.y = ''; } } class SelectableModel { constructor() { this.title = ''; this.titleFull = ''; this.linkTitle = ''; this.caption = ''; this.link = ''; } } // ========================= // ========================= var AnimationType; (function (AnimationType) { AnimationType["Scale"] = "scale"; AnimationType["Fade"] = "fade"; AnimationType["Flip"] = "flip"; AnimationType["JackInTheBox"] = "jackInTheBox"; })(AnimationType || (AnimationType = {})); // ========================= // Scale // ========================= const scaleIn = animation([ style({ opacity: 0, transform: "scale(0.5)" }), animate("{{time}} cubic-bezier(0.785, 0.135, 0.15, 0.86)", style({ opacity: 1, transform: "scale(1)" })) ]); const scaleOut = animation([ animate("{{time}} cubic-bezier(0.785, 0.135, 0.15, 0.86)", style({ opacity: 0, transform: "scale(0.5)" })) ]); // ========================= // Fade // ========================= const fadeIn = animation([ style({ opacity: 0 }), animate("{{time}} cubic-bezier(0.785, 0.135, 0.15, 0.86)", style({ opacity: 1 })) ]); const fadeOut = animation([ animate("{{time}} cubic-bezier(0.785, 0.135, 0.15, 0.86)", style({ opacity: 0 })) ]); // ========================= // Flip // ========================= const flipIn = animation([ animate("{{time}} cubic-bezier(0.785, 0.135, 0.15, 0.86)", keyframes([ style({ opacity: 1, transform: "perspective(400px) rotate3d(1, 0, 0, 90deg)", offset: 0 }), style({ transform: "perspective(400px)", offset: 1 }) ])) ]); const flipOut = animation([ // just hide it ]); // ========================= // Jack in the box // ========================= const jackIn = animation([ animate("{{time}} ease-in", keyframes([ style({ animationFillMode: "forwards", transform: "scale(0.1) rotate(30deg)", transformOrigin: "center bottom", offset: 0 }), style({ transform: "rotate(-10deg)", offset: 0.5 }), style({ transform: "rotate(3deg)", offset: 0.7 }), style({ transform: "perspective(400px)", offset: 1 }) ])) ]); const jackOut = animation([ // just hide it ]); class NoSanitizePipe { constructor(domSanitizer) { this.domSanitizer = domSanitizer; } transform(html) { if (html) return this.domSanitizer.bypassSecurityTrustHtml(html); else return ''; } } NoSanitizePipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.4", ngImport: i0, type: NoSanitizePipe, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); NoSanitizePipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "12.0.0", version: "12.2.4", ngImport: i0, type: NoSanitizePipe, name: "noSanitize" }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.4", ngImport: i0, type: NoSanitizePipe, decorators: [{ type: Pipe, args: [{ name: 'noSanitize' }] }], ctorParameters: function () { return [{ type: i1.DomSanitizer }]; } }); class HeaderComponent { constructor() { this.headerList = []; } ngOnInit() { } } HeaderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.4", ngImport: i0, type: HeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); HeaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.4", type: HeaderComponent, selector: "mt-header", inputs: { headerList: "headerList" }, ngImport: i0, template: "<div class=\"toolbar\" role=\"banner\" *ngIf=\"headerList.length\" >\n <ng-container *ngFor=\"let headerItem of headerList; let i = index\" class=\"wrap\">\n <div *ngIf=\"headerItem.enabled\">\n <a target=\"_blank\" rel=\"noopener\" [href]=\"headerItem.href\" [title]=\"headerItem.title\">\n <div [innerHtml]=\"headerItem.icon | noSanitize\"> </div>\n </a>\n </div>\n </ng-container>\n</div>", styles: [".toolbar{position:absolute;top:0;left:0;right:0;height:60px;display:flex;align-items:center;flex-direction:row-reverse;color:#f93;font-weight:600;z-index:100}.toolbar div{margin:0 6px}.toolbar a{margin:0 8px}.toolbar a:last-child{margin:0 16px}.toolbar a:hover{opacity:.8}\n"], directives: [{ type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "noSanitize": NoSanitizePipe } }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.4", ngImport: i0, type: HeaderComponent, decorators: [{ type: Component, args: [{ selector: 'mt-header', templateUrl: './header.component.html', styleUrls: ['./header.component.scss'] }] }], ctorParameters: function () { return []; }, propDecorators: { headerList: [{ type: Input }] } }); class SwipeDirective { constructor() { this.next = new EventEmitter(); this.previous = new EventEmitter(); this.swipeCoord = [0, 0]; this.swipeTime = new Date().getTime(); } onSwipeStart($event) { this.onSwipe($event, 'start'); } onSwipeEnd($event) { this.onSwipe($event, 'end'); } onSwipe(e, when) { this.swipe(e, when); } swipe(e, when) { const coord = [e.changedTouches[0].clientX, e.changedTouches[0].clientY]; const time = new Date().getTime(); if (when === 'start') { this.swipeCoord = coord; this.swipeTime = time; } else if (when === 'end') { const direction = [coord[0] - this.swipeCoord[0], coord[1] - this.swipeCoord[1]]; const duration = time - this.swipeTime; if (duration < 1000 // && Math.abs(direction[0]) > 30 // Long enough && Math.abs(direction[0]) > Math.abs(direction[1] * 3)) { // Horizontal enough const swipeDir = direction[0] < 0 ? 'next' : 'previous'; if (swipeDir === 'next') { this.next.emit(); } else { this.previous.emit(); } } } } } SwipeDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.4", ngImport: i0, type: SwipeDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); SwipeDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.4", type: SwipeDirective, selector: "[swipe]", outputs: { next: "next", previous: "previous" }, host: { listeners: { "touchstart": "onSwipeStart($event)", "touchend": "onSwipeEnd($event)" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.4", ngImport: i0, type: SwipeDirective, decorators: [{ type: Directive, args: [{ selector: '[swipe]' }] }], ctorParameters: function () { return []; }, propDecorators: { next: [{ type: Output }], previous: [{ type: Output }], onSwipeStart: [{ type: HostListener, args: ['touchstart', ['$event']] }], onSwipeEnd: [{ type: HostListener, args: ['touchend', ['$event']] }] } }); class MtPortfolioComponent { constructor(sanitizer) { this.sanitizer = sanitizer; this.portfolioList = []; this.animationType = 'scale'; this.header = []; this.currentSlide = 0; } onPreviousClick() { const previous = this.currentSlide - 1; this.currentSlide = previous < 0 ? this.portfolioList.length - 1 : previous; // console.log("previous clicked, new current slide is: ", this.currentSlide); } onNextClick() { const next = this.currentSlide + 1; this.currentSlide = next === this.portfolioList.length ? 0 : next; // console.log("next clicked, new current slide is: ", this.currentSlide); } ngOnInit() { this.preloadImages(); if (location.hash !== "") { const locationHash = this.portfolioList.find(s => { var _a; return ((_a = s.selectable) === null || _a === void 0 ? void 0 : _a.link) == location.hash; }) ? this.portfolioList.find(s => { var _a; return ((_a = s.selectable) === null || _a === void 0 ? void 0 : _a.link) == location.hash; }) : new PortfolioModel(); if (locationHash) { this.currentSlide = this.portfolioList.indexOf(locationHash); } } } onSlideClick(slide) { // const next = this.currentSlide + 1; this.currentSlide = this.portfolioList.indexOf(slide); } preloadImages() { for (const slide of this.portfolioList) { new Image().src = slide.src; } } } MtPortfolioComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.4", ngImport: i0, type: MtPortfolioComponent, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component }); MtPortfolioComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.4", type: MtPortfolioComponent, selector: "mt-portfolio", inputs: { portfolioList: "portfolioList", animationType: "animationType", header: "header" }, ngImport: i0, template: "<mt-header [headerList]=\"header\"></mt-header>\n<div class=\"container\">\n <div class=\"carousel\" *ngIf=\"portfolioList.length\">\n <ng-container *ngFor=\"let slide of portfolioList; let i = index\">\n <picture [@slideAnimation]=\"animationType\" swipe (next)=\"onNextClick()\" (previous)=\"onPreviousClick()\">\n <source media=\"(min-width:650px)\" srcset=\"{{slide.srcLarge? slide.srcLarge : slide.src}}\">\n <source media=\"(min-width:465px)\" srcset=\"{{slide.srcMedium? slide.srcMedium : slide.src}}\">\n <img *ngIf=\"i === currentSlide\" [src]=\"slide.src\" [alt]=\"slide.alt\" class=\"slide\"\n [@slideAnimation]=\"animationType\" />\n </picture>\n <div *ngIf=\"i === currentSlide\" class=\"my-name-div\" [style.right]=\"slide.x\" [style.top]=\"slide.y\"\n [@slideAnimation]=\"animationType\">\n <h1 class=\"header\" *ngIf=\"slide.selectable?.title\">\n {{slide.selectable?.title}}<span>{{slide.selectable?.titleFull}}</span></h1>\n <p *ngIf=\"slide.selectable?.caption\" [innerHTML]=\"slide.selectable?.caption | noSanitize\"></p>\n </div>\n\n </ng-container>\n\n\n <div class=\"control next selectable\">\n\n <div *ngFor=\"let slide of portfolioList; let i = index\">\n\n\n <a *ngIf=\"slide.selectable\" href=\"{{slide.selectable.link}}\"\n (click)=\"onSlideClick(slide)\">{{slide.selectable.linkTitle}}</a>\n </div>\n </div>\n\n <!-- controls -->\n <button *ngIf=\"currentSlide != 0\" class=\"control prev\" (click)=\"onPreviousClick()\">\n <span class=\"arrow left\"></span>\n </button>\n <button class=\"control next\" (click)=\"onNextClick()\">\n <span class=\"arrow right\"></span>\n </button>\n </div>\n</div>", styles: [".container{position:fixed;display:block;width:100vw;height:100vh;height:-webkit-fill-available}:host{flex:1}.carousel{position:relative;height:100%;width:100%;overflow:hidden}.slide{position:absolute;top:0;left:0;width:100%;height:100%;-o-object-fit:cover;object-fit:cover;transition:transform .15s cubic-bezier(.25,.46,.45,.84)}.slide:hover{transform:scale(1.025)}.control{border:none;background-color:transparent;outline:0;position:absolute;cursor:pointer;display:flex;flex-direction:column;justify-content:center;padding:.5em;color:#fff;font-weight:bold;font-size:3em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;height:20%;opacity:80%;transition:opacity .15s cubic-bezier(.25,.46,.45,.84);bottom:0}.control.selectable{bottom:40vh;text-align:center;font-size:large}.control.selectable a{color:#a9a9a9;text-decoration:none;padding:5px;border:2px solid #ff9933;display:block;margin-bottom:5px}.control.selectable a:hover,.control.selectable a:focus{color:#fff}.control:hover,.control:focus{opacity:1}.control.next{right:0}.control.prev{left:0}.arrow{display:block;border-left:.1em solid white;border-bottom:.1em solid white;width:.5em;height:.5em}.arrow.left{transform:rotate(45deg)}.arrow.right{transform:rotate(225deg)}.header{color:#f93;font-size:50px;font-weight:bold;font-family:monospace;letter-spacing:7px;cursor:pointer}@media (max-width: 641px){.header{font-size:40px}}.my-name-div{position:absolute;color:#f0f8ff;width:40vw}.header span{transition:1s linear}.header:hover span:nth-child(1){margin-right:5px}.header:hover span:nth-child(2){margin-left:30px}.header:hover span{color:#fff;text-shadow:0 0 10px #fff,0 0 20px #fff,0 0 40px #fff}\n"], components: [{ type: HeaderComponent, selector: "mt-header", inputs: ["headerList"] }], directives: [{ type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: SwipeDirective, selector: "[swipe]", outputs: ["next", "previous"] }], pipes: { "noSanitize": NoSanitizePipe }, animations: [ trigger("slideAnimation", [ /* scale */ transition("void => scale", [ useAnimation(scaleIn, { params: { time: "1500ms" } }) ]), transition("scale => void", [ useAnimation(scaleOut, { params: { time: "1500ms" } }) ]), /* fade */ transition("void => fade", [ useAnimation(fadeIn, { params: { time: "1750ms" } }) ]), transition("fade => void", [ useAnimation(fadeOut, { params: { time: "1750ms" } }) ]), /* flip */ transition("void => flip", [ useAnimation(flipIn, { params: { time: "500ms" } }) ]), transition("flip => void", [ useAnimation(flipOut, { params: { time: "500ms" } }) ]), /* JackInTheBox */ transition("void => jackInTheBox", [ useAnimation(jackIn, { params: { time: "700ms" } }) ]), transition("jackInTheBox => void", [ useAnimation(jackOut, { params: { time: "700ms" } }) ]) ]) ] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.4", ngImport: i0, type: MtPortfolioComponent, decorators: [{ type: Component, args: [{ selector: 'mt-portfolio', templateUrl: './mt-portfolio.component.html', styleUrls: ['./mt-portfolio.component.scss'], animations: [ trigger("slideAnimation", [ /* scale */ transition("void => scale", [ useAnimation(scaleIn, { params: { time: "1500ms" } }) ]), transition("scale => void", [ useAnimation(scaleOut, { params: { time: "1500ms" } }) ]), /* fade */ transition("void => fade", [ useAnimation(fadeIn, { params: { time: "1750ms" } }) ]), transition("fade => void", [ useAnimation(fadeOut, { params: { time: "1750ms" } }) ]), /* flip */ transition("void => flip", [ useAnimation(flipIn, { params: { time: "500ms" } }) ]), transition("flip => void", [ useAnimation(flipOut, { params: { time: "500ms" } }) ]), /* JackInTheBox */ transition("void => jackInTheBox", [ useAnimation(jackIn, { params: { time: "700ms" } }) ]), transition("jackInTheBox => void", [ useAnimation(jackOut, { params: { time: "700ms" } }) ]) ]) ] }] }], ctorParameters: function () { return [{ type: i1.DomSanitizer }]; }, propDecorators: { portfolioList: [{ type: Input }], animationType: [{ type: Input }], header: [{ type: Input }] } }); class MtPortfolioModule { } MtPortfolioModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.4", ngImport: i0, type: MtPortfolioModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); MtPortfolioModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.4", ngImport: i0, type: MtPortfolioModule, declarations: [HeaderComponent, NoSanitizePipe, SwipeDirective, MtPortfolioComponent], imports: [CommonModule, BrowserAnimationsModule], exports: [MtPortfolioComponent] }); MtPortfolioModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.4", ngImport: i0, type: MtPortfolioModule, imports: [[ CommonModule, BrowserAnimationsModule ]] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.4", ngImport: i0, type: MtPortfolioModule, decorators: [{ type: NgModule, args: [{ declarations: [ HeaderComponent, NoSanitizePipe, SwipeDirective, MtPortfolioComponent ], imports: [ CommonModule, BrowserAnimationsModule ], exports: [ MtPortfolioComponent ] }] }] }); /* * Public API Surface of mt-portfolio */ /** * Generated bundle index. Do not edit. */ export { MtPortfolioComponent, MtPortfolioModule }; //# sourceMappingURL=mt-portfolio.js.map