mirror of https://github.com/Ombi-app/Ombi
parent
4cd4a1ef50
commit
3ca0aebfd6
@ -1,62 +1,59 @@
|
|||||||
<mat-sidenav-container *ngIf="showNav" class="sidenav-container">
|
<mat-sidenav-container *ngIf="showNav" class="sidenav-container">
|
||||||
<mat-sidenav #drawer class="sidenav" fixedInViewport="true"
|
<mat-sidenav #drawer class="sidenav" fixedInViewport="true" [attr.role]="(isHandset$ | async) ? 'dialog' : 'navigation'" [mode]="(isHandset$ | async) ? 'over' : 'side'" [opened]="!(isHandset$ | async)">
|
||||||
[attr.role]="(isHandset$ | async) ? 'dialog' : 'navigation'" [mode]="(isHandset$ | async) ? 'over' : 'side'"
|
<mat-toolbar>{{applicationName}}</mat-toolbar>
|
||||||
[opened]="!(isHandset$ | async)">
|
<mat-nav-list>
|
||||||
<mat-toolbar>{{applicationName}}</mat-toolbar>
|
<span *ngFor="let nav of navItems">
|
||||||
<mat-nav-list>
|
|
||||||
<span *ngFor="let nav of navItems">
|
|
||||||
<a *ngIf="nav.requiresAdmin && isAdmin || !nav.requiresAdmin" mat-list-item [routerLink]="nav.link"
|
<a *ngIf="nav.requiresAdmin && isAdmin || !nav.requiresAdmin" mat-list-item [routerLink]="nav.link"
|
||||||
[routerLinkActive]="getTheme()">
|
[routerLinkActive]="getTheme()">
|
||||||
<mat-icon aria-label="Side nav toggle icon">{{nav.icon}}</mat-icon>
|
<mat-icon aria-label="Side nav toggle icon">{{nav.icon}}</mat-icon>
|
||||||
{{nav.name | translate}}
|
{{nav.name | translate}}
|
||||||
</a> </span>
|
</a> </span>
|
||||||
|
|
||||||
<a class="bottom-nav-link" mat-list-item
|
<a class="bottom-nav-link" mat-list-item [routerLinkActive]="theme === 'dark' ? 'active-list-item-dark' : 'active-list-item'" aria-label="Toggle sidenav" (click)="logOut();">
|
||||||
[routerLinkActive]="theme === 'dark' ? 'active-list-item-dark' : 'active-list-item'" aria-label="Toggle sidenav"
|
<mat-icon aria-label="Side nav toggle icon">exit_to_app</mat-icon>
|
||||||
(click)="logOut();">
|
{{ 'NavigationBar.Logout' | translate }}
|
||||||
<mat-icon aria-label="Side nav toggle icon">exit_to_app</mat-icon>
|
</a>
|
||||||
{{ 'NavigationBar.Logout' | translate }}
|
|
||||||
</a>
|
|
||||||
|
|
||||||
|
|
||||||
</mat-nav-list>
|
</mat-nav-list>
|
||||||
</mat-sidenav>
|
</mat-sidenav>
|
||||||
<mat-sidenav-content>
|
<mat-sidenav-content>
|
||||||
<mat-toolbar color="primary">
|
<mat-toolbar color="primary">
|
||||||
<button type="button" aria-label="Toggle sidenav" mat-icon-button (click)="drawer.toggle()"
|
<button type="button" aria-label="Toggle sidenav" mat-icon-button (click)="drawer.toggle()" *ngIf="isHandset$ | async">
|
||||||
*ngIf="isHandset$ | async">
|
|
||||||
<mat-icon aria-label="Side nav toggle icon">menu</mat-icon>
|
<mat-icon aria-label="Side nav toggle icon">menu</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="col-md-10 offset-md-1 col-10">
|
<div class="col-md-10 offset-md-1 col-10">
|
||||||
<span class="middle justify-content-center align-items-center">
|
<span class="middle justify-content-center align-items-center">
|
||||||
<!-- Search Bar -->
|
<!-- Search Bar -->
|
||||||
|
<div style="width: 50%;">
|
||||||
<app-nav-search></app-nav-search>
|
<app-nav-search></app-nav-search>
|
||||||
|
</div>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-1">
|
<div class="col-1">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a mat-list-item (click)="switchTheme()">
|
<a mat-list-item (click)="switchTheme()">
|
||||||
<mat-icon *ngIf="theme === 'dark'" aria-label="Side nav toggle icon">brightness_7</mat-icon>
|
<mat-icon *ngIf="theme === 'dark'" aria-label="Side nav toggle icon">brightness_7</mat-icon>
|
||||||
<mat-icon *ngIf="theme === 'light'" aria-label="Side nav toggle icon">brightness_4</mat-icon>
|
<mat-icon *ngIf="theme === 'light'" aria-label="Side nav toggle icon">brightness_4</mat-icon>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</mat-toolbar>
|
</mat-toolbar>
|
||||||
|
|
||||||
<!-- Page -->
|
<!-- Page -->
|
||||||
<ng-container *ngTemplateOutlet="template"></ng-container>
|
<ng-container *ngTemplateOutlet="template"></ng-container>
|
||||||
|
|
||||||
|
|
||||||
</mat-sidenav-content>
|
</mat-sidenav-content>
|
||||||
</mat-sidenav-container>
|
</mat-sidenav-container>
|
||||||
|
|
||||||
<div *ngIf="!showNav">
|
<div *ngIf="!showNav">
|
||||||
<ng-container *ngTemplateOutlet="template"></ng-container>
|
<ng-container *ngTemplateOutlet="template"></ng-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ng-template #template>
|
<ng-template #template>
|
||||||
<router-outlet> </router-outlet>
|
<router-outlet> </router-outlet>
|
||||||
</ng-template>
|
</ng-template>
|
@ -1,30 +1,42 @@
|
|||||||
<input class="form-control quater-width search-bar" type="text" [(ngModel)]="selectedItem"
|
<!-- <input class="form-control quater-width search-bar" type="text" [(ngModel)]="selectedItem" placeholder="{{'NavigationBar.Search' | translate}}"
|
||||||
placeholder="{{'NavigationBar.Search' | translate}}" aria-label="Search" [ngbTypeahead]="searchModel"
|
aria-label="Search" [ngbTypeahead]="searchModel" [resultFormatter]="formatter" [inputFormatter]="formatter" [resultTemplate]="template" (selectItem)="selected($event)">
|
||||||
[resultFormatter]="formatter" [inputFormatter]="formatter" [resultTemplate]="template" (selectItem)="selected($event)">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ng-template #template let-result="result">
|
<ng-template #template let-result="result">
|
||||||
<div *ngIf="result.mediaType === 'movie'">
|
|
||||||
<i class="fa fa-film"></i>
|
</ng-template> -->
|
||||||
<span >{{result.title}}</span>
|
|
||||||
</div>
|
<form [formGroup]='searchForm'>
|
||||||
<div *ngIf="result.mediaType === 'tv'">
|
<mat-form-field floatLabel="never" style="width: 100%;">
|
||||||
<i class="fa fa-tv"></i>
|
<input matInput placeholder="{{'NavigationBar.Search' | translate}}" [matAutocomplete]="auto" formControlName='input'>
|
||||||
|
</mat-form-field>
|
||||||
<span>{{result.title}}</span>
|
|
||||||
</div>
|
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)" [displayWith]="displayFn">
|
||||||
|
<mat-option *ngIf="searching" color="accent">
|
||||||
|
<mat-spinner diameter="50"></mat-spinner>
|
||||||
|
</mat-option>
|
||||||
|
<ng-container *ngIf="!searching">
|
||||||
|
<mat-option *ngFor="let result of results" [value]="result">
|
||||||
|
<div *ngIf="result.mediaType === 'movie'">
|
||||||
|
<i class="fa fa-film"></i>
|
||||||
|
<span>{{result.title}}</span>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="result.mediaType === 'tv'">
|
||||||
|
<i class="fa fa-tv"></i>
|
||||||
|
|
||||||
|
<span>{{result.title}}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="result.mediaType === 'Artist'">
|
||||||
|
<i class="fa fa-music"></i>
|
||||||
|
|
||||||
<div *ngIf="result.mediaType === 'Artist'">
|
<span>{{result.title}}</span>
|
||||||
<i class="fa fa-music"></i>
|
</div>
|
||||||
|
|
||||||
<span>{{result.title}}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div *ngIf="result.mediaType === 'person'">
|
<div *ngIf="result.mediaType === 'person'">
|
||||||
<i class="fa fa-user"></i>
|
<i class="fa fa-user"></i>
|
||||||
<span >{{result.title}}</span>
|
<span>{{result.title}}</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- Collection -->
|
</mat-option>
|
||||||
<!-- <i class="fa fa-file-video-o" aria-hidden="true"></i> -->
|
</ng-container>
|
||||||
</ng-template>
|
</mat-autocomplete>
|
||||||
|
</form>
|
@ -1,49 +1,32 @@
|
|||||||
$ombi-primary:#3f3f3f;
|
$ombi-primary:#3f3f3f;
|
||||||
$ombi-primary-darker:#2b2b2b;
|
$ombi-primary-darker:#2b2b2b;
|
||||||
$ombi-accent: #258a6d;
|
$ombi-accent: #258a6d;
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
.quater-width {
|
.quater-width {
|
||||||
width: 15em !important;
|
width: 15em !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.quater-width {
|
.quater-width {
|
||||||
width: 25em;
|
width: 25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.autocomplete-img {
|
.autocomplete-img {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
height: 63px;
|
height: 63px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-option {
|
.mat-option {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
line-height: 50px;
|
line-height: 50px;
|
||||||
padding: 0px 5px;
|
padding: 0px 5px;
|
||||||
}
|
|
||||||
|
|
||||||
::ng-deep ngb-typeahead-window.dropdown-menu {
|
|
||||||
background-color: $ombi-primary;
|
|
||||||
overflow: auto;
|
|
||||||
height: 33em;
|
|
||||||
}
|
|
||||||
|
|
||||||
::ng-deep ngb-typeahead-window button.dropdown-item {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
::ng-deep ngb-typeahead-window .dropdown-item.active,
|
|
||||||
.dropdown-item:active {
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: $ombi-accent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-bar {
|
.search-bar {
|
||||||
background-color: $ombi-primary-darker;
|
background-color: $ombi-primary-darker;
|
||||||
border: solid 1px $ombi-primary-darker;
|
border: solid 1px $ombi-primary-darker;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-bar:focus {
|
.search-bar:focus {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
}
|
}
|
@ -1,56 +1,78 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from "rxjs";
|
||||||
import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';
|
import {
|
||||||
|
debounceTime,
|
||||||
|
distinctUntilChanged,
|
||||||
|
switchMap,
|
||||||
|
tap,
|
||||||
|
finalize,
|
||||||
|
} from "rxjs/operators";
|
||||||
|
|
||||||
import { SearchV2Service } from '../services/searchV2.service';
|
import { empty, of } from "rxjs";
|
||||||
import { IMultiSearchResult } from '../interfaces';
|
import { SearchV2Service } from "../services/searchV2.service";
|
||||||
import { Router } from '@angular/router';
|
import { IMultiSearchResult } from "../interfaces";
|
||||||
import { NgbTypeaheadSelectItemEvent } from '@ng-bootstrap/ng-bootstrap';
|
import { Router } from "@angular/router";
|
||||||
|
import { NgbTypeaheadSelectItemEvent } from "@ng-bootstrap/ng-bootstrap";
|
||||||
|
import { FormGroup, FormBuilder } from "@angular/forms";
|
||||||
|
import { MatAutocompleteSelectedEvent } from "@angular/material";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-nav-search',
|
selector: "app-nav-search",
|
||||||
templateUrl: './nav-search.component.html',
|
templateUrl: "./nav-search.component.html",
|
||||||
styleUrls: ['./nav-search.component.scss']
|
styleUrls: ["./nav-search.component.scss"],
|
||||||
})
|
})
|
||||||
export class NavSearchComponent {
|
export class NavSearchComponent implements OnInit {
|
||||||
|
public selectedItem: string;
|
||||||
|
public results: IMultiSearchResult[];
|
||||||
|
public searching = false;
|
||||||
|
|
||||||
public selectedItem: string;
|
public searchForm: FormGroup;
|
||||||
|
|
||||||
public searching = false;
|
|
||||||
public searchFailed = false;
|
|
||||||
|
|
||||||
public formatter = (result: IMultiSearchResult) => {
|
|
||||||
return result.title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public searchModel = (text$: Observable<string>) =>
|
|
||||||
text$.pipe(
|
|
||||||
debounceTime(600),
|
|
||||||
distinctUntilChanged(),
|
|
||||||
switchMap(term => term.length < 2 ? []
|
|
||||||
: this.searchService.multiSearch(term)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
constructor(private searchService: SearchV2Service, private router: Router) {
|
constructor(
|
||||||
|
private searchService: SearchV2Service,
|
||||||
|
private router: Router,
|
||||||
|
private fb: FormBuilder
|
||||||
|
) {}
|
||||||
|
|
||||||
}
|
public async ngOnInit() {
|
||||||
|
this.searchForm = this.fb.group({
|
||||||
|
input: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.searchForm
|
||||||
|
.get("input")
|
||||||
|
.valueChanges.pipe(
|
||||||
|
debounceTime(600),
|
||||||
|
tap(() => (this.searching = true)),
|
||||||
|
switchMap((value: string) => {
|
||||||
|
if (value) {
|
||||||
|
return this.searchService
|
||||||
|
.multiSearch(value)
|
||||||
|
.pipe(finalize(() => (this.searching = false)));
|
||||||
|
}
|
||||||
|
return empty().pipe(finalize(() => (this.searching = false)));
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.subscribe((r) => (this.results = r));
|
||||||
|
}
|
||||||
|
|
||||||
public selected(event: NgbTypeaheadSelectItemEvent) {
|
public selected(event: MatAutocompleteSelectedEvent) {
|
||||||
if (event.item.mediaType == "movie") {
|
const val = event.option.value as IMultiSearchResult;
|
||||||
this.router.navigate([`details/movie/${event.item.id}`]);
|
if (val.mediaType == "movie") {
|
||||||
return;
|
this.router.navigate([`details/movie/${val.id}`]);
|
||||||
} else if (event.item.mediaType == "tv") {
|
return;
|
||||||
this.router.navigate([`details/tv/${event.item.id}/true`]);
|
} else if (val.mediaType == "tv") {
|
||||||
return;
|
this.router.navigate([`details/tv/${val.id}/true`]);
|
||||||
} else if (event.item.mediaType == "person") {
|
return;
|
||||||
this.router.navigate([`discover/actor/${event.item.id}`]);
|
} else if (val.mediaType == "person") {
|
||||||
return;
|
this.router.navigate([`discover/actor/${val.id}`]);
|
||||||
} else if (event.item.mediaType == "Artist") {
|
return;
|
||||||
this.router.navigate([`details/artist/${event.item.id}`]);
|
} else if (val.mediaType == "Artist") {
|
||||||
return;
|
this.router.navigate([`details/artist/${val.id}`]);
|
||||||
}
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
displayFn(result: IMultiSearchResult) {
|
||||||
|
if (result) { return result.title; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in new issue