Adding collections to the search page

This commit is contained in:
Zoe Roux 2020-04-04 15:30:26 +02:00
parent 038e071450
commit 44753c4634
8 changed files with 218 additions and 8 deletions

View File

@ -34,6 +34,7 @@ import {FallbackDirective} from "./misc/fallback.directive";
import {AuthModule} from "./auth/auth.module"; import {AuthModule} from "./auth/auth.module";
import {AuthRoutingModule} from "./auth/auth-routing.module"; import {AuthRoutingModule} from "./auth/auth-routing.module";
import { TrailerDialogComponent } from './trailer-dialog/trailer-dialog.component'; import { TrailerDialogComponent } from './trailer-dialog/trailer-dialog.component';
import {CollectionsListComponent} from "./collection-list/collections-list.component";
@NgModule({ @NgModule({
@ -50,7 +51,8 @@ import { TrailerDialogComponent } from './trailer-dialog/trailer-dialog.componen
ShowsListComponent, ShowsListComponent,
PasswordValidator, PasswordValidator,
FallbackDirective, FallbackDirective,
TrailerDialogComponent TrailerDialogComponent,
CollectionsListComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,

View File

@ -0,0 +1,10 @@
<div class="scroll-row mb-5">
<div class="collections-container" #scrollView (scroll)="onScroll()">
<a class="collection" *ngFor="let collection of this.collections" routerLink="/collection/{{collection.slug}}" href="/collection/{{collection.slug}}">
<div matRipple [style.background-image]="getThumb(collection.slug)"> </div>
<p class="title">{{collection.name}}</p>
</a>
</div>
<button mat-raised-button color="accent" class="scrollBtn leftBtn d-none" #leftBtn (click)="scrollLeft()"><mat-icon>arrow_left</mat-icon></button>
<button mat-raised-button color="accent" class="scrollBtn rightBtn" #rightBtn (click)="scrollRight()"><mat-icon>arrow_right</mat-icon></button>
</div>

View File

@ -0,0 +1,142 @@
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss/mixins/breakpoints";
.collections-container
{
display: flex;
padding-left: 15px;
padding-right: 15px;
overflow-x: auto;
min-width: 100%;
flex-shrink: 0;
flex-direction: row;
&::-webkit-scrollbar
{
height: 4px;
background: transparent;
}
&::-webkit-scrollbar-thumb
{
background-color: #999;
border-radius: 90px;
&:host-context(.hoverEnabled) &:hover
{
background-color: rgb(134, 127, 127);
}
}
}
.collection
{
width: 33%;
min-width: 120px;
max-width: 200px;
list-style: none;
padding: .5em;
text-decoration: none;
color: inherit;
outline: none;
flex-shrink: 0;
flex-grow: 0;
@include media-breakpoint-up(sm)
{
width: 25%;
}
@include media-breakpoint-up(md)
{
width: 20%;
padding: 1em;
}
@include media-breakpoint-up(lg)
{
width: 18%;
}
@include media-breakpoint-up(xl)
{
width: 15%;
}
&:focus, &:hover
{
> div
{
outline: solid var(--accentColor);
}
> .title
{
text-decoration: underline;
}
}
> div
{
width: 100%;
height: 0;
padding-top: 147.0588%;
background-size: cover;
background-color: #333333;
}
> p
{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
margin-bottom: 0px;
opacity: 1;
}
&:host-context(.hoverEnabled) &:hover
{
cursor: pointer;
}
}
.scroll-row
{
position: relative;
&:host-context(.hoverEnabled) &:hover
{
.scrollBtn
{
display: block;
}
}
}
.scrollBtn
{
padding: 0;
outline: none;
min-width: 0;
position: absolute;
top: 30%;
bottom: 40%;
display: none;
&.leftBtn
{
left: 0;
padding-left: 10px;
padding-right: 2px;
}
&.rightBtn
{
right: 0;
padding-right: 10px;
padding-left: 2px;
}
}

View File

@ -0,0 +1,50 @@
import {Component, ElementRef, Input, ViewChild} from "@angular/core";
import {Collection} from "../../models/collection";
import {MatButton} from "@angular/material/button";
import {DomSanitizer} from "@angular/platform-browser";
@Component({
selector: 'app-collections-list',
templateUrl: './collections-list.component.html',
styleUrls: ['./collections-list.component.scss']
})
export class CollectionsListComponent
{
@Input() collections: Collection[];
@ViewChild("scrollView", {static: true}) private scrollView: ElementRef;
@ViewChild("leftBtn", {static: false}) private leftBtn: MatButton;
@ViewChild("rightBtn", {static: false}) private rightBtn: MatButton;
constructor(private sanitizer: DomSanitizer)
{
}
scrollLeft()
{
let scroll: number = this.scrollView.nativeElement.offsetWidth * 0.80;
this.scrollView.nativeElement.scrollBy({top: 0, left: -scroll, behavior: "smooth"});
}
scrollRight()
{
let scroll: number = this.scrollView.nativeElement.offsetWidth * 0.80;
this.scrollView.nativeElement.scrollBy({top: 0, left: scroll, behavior: "smooth"});
}
onScroll()
{
if (this.scrollView.nativeElement.scrollLeft <= 0)
this.leftBtn._elementRef.nativeElement.classList.add("d-none");
else
this.leftBtn._elementRef.nativeElement.classList.remove("d-none");
if (this.scrollView.nativeElement.scrollLeft >= this.scrollView.nativeElement.scrollWidth - this.scrollView.nativeElement.clientWidth)
this.rightBtn._elementRef.nativeElement.classList.add("d-none");
else
this.rightBtn._elementRef.nativeElement.classList.remove("d-none");
}
getThumb(slug: string)
{
return this.sanitizer.bypassSecurityTrustStyle("url(/poster/" + slug + ")");
}
}

View File

@ -1,3 +1,7 @@
<div *ngIf="items.collections.length > 0" class="container-fluid mt-3">
<h3>Collections</h3>
</div>
<app-collections-list [collections]="items.collections"></app-collections-list>
<div *ngIf="items.shows.length > 0" class="container-fluid mt-3"> <div *ngIf="items.shows.length > 0" class="container-fluid mt-3">
<h3>Shows</h3> <h3>Shows</h3>
</div> </div>

View File

@ -1,6 +1,6 @@
import { Component, OnInit, OnDestroy } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute } from "@angular/router"; import { ActivatedRoute } from "@angular/router";
import { SearchResut } from "../../models/search-result"; import { SearchResult } from "../../models/search-result";
import { Title } from "@angular/platform-browser"; import { Title } from "@angular/platform-browser";
@Component({ @Component({
@ -10,7 +10,7 @@ import { Title } from "@angular/platform-browser";
}) })
export class SearchComponent implements OnInit, OnDestroy export class SearchComponent implements OnInit, OnDestroy
{ {
items: SearchResut; items: SearchResult;
constructor(private route: ActivatedRoute, private title: Title) { } constructor(private route: ActivatedRoute, private title: Title) { }

View File

@ -4,19 +4,19 @@ import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router'; import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { EMPTY, Observable } from 'rxjs'; import { EMPTY, Observable } from 'rxjs';
import { catchError } from 'rxjs/operators'; import { catchError } from 'rxjs/operators';
import { SearchResut } from "../../models/search-result"; import { SearchResult } from "../../models/search-result";
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class SearchResolverService implements Resolve<SearchResut> export class SearchResolverService implements Resolve<SearchResult>
{ {
constructor(private http: HttpClient, private snackBar: MatSnackBar) { } constructor(private http: HttpClient, private snackBar: MatSnackBar) { }
resolve(route: ActivatedRouteSnapshot): SearchResut | Observable<SearchResut> | Promise<SearchResut> resolve(route: ActivatedRouteSnapshot): SearchResult | Observable<SearchResult> | Promise<SearchResult>
{ {
let query: string = route.paramMap.get("query"); let query: string = route.paramMap.get("query");
return this.http.get<SearchResut>("api/search/" + query).pipe(catchError((error: HttpErrorResponse) => return this.http.get<SearchResult>("api/search/" + query).pipe(catchError((error: HttpErrorResponse) =>
{ {
console.log(error.status + " - " + error.message); console.log(error.status + " - " + error.message);
this.snackBar.open("An unknow error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 }); this.snackBar.open("An unknow error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });

View File

@ -3,10 +3,12 @@ import { Episode } from "./episode";
import { People } from "./people"; import { People } from "./people";
import { Studio } from "./studio"; import { Studio } from "./studio";
import { Genre } from "./genre"; import { Genre } from "./genre";
import {Collection} from "./collection";
export interface SearchResut export interface SearchResult
{ {
query: string; query: string;
collections: Collection[];
shows: Show[]; shows: Show[];
episodes: Episode[]; episodes: Episode[];
people: People[]; people: People[];