mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Cleaning up navigation height & edit page
This commit is contained in:
parent
3de2e74ecf
commit
f764d8bbae
@ -38,7 +38,10 @@
|
||||
"./node_modules/jquery/dist/jquery.min.js",
|
||||
"./node_modules/bootstrap/dist/js/bootstrap.bundle.min.js",
|
||||
"./node_modules/hls.js/dist/hls.js"
|
||||
]
|
||||
],
|
||||
"stylePreprocessorOptions": {
|
||||
"includePaths": ["src"]
|
||||
}
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
|
@ -1,4 +1,4 @@
|
||||
<header id="nav" style="height: 68px;">
|
||||
<header id="nav">
|
||||
<div class="fixed-top">
|
||||
<nav id="toolbar" class="navbar navbar-dark bg-secondary">
|
||||
<a class="navbar-brand nav-item ml-3" routerLink="/">
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
<ul class="navbar-nav flex-row">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" routerLink="/browse" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">All</a>
|
||||
<a class="nav-link" routerLink="/browse" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}">All</a>
|
||||
</li>
|
||||
<li class="nav-item" *ngFor="let library of this.libraries">
|
||||
<a class="nav-link" routerLink="/browse/{{library.slug}}" routerLinkActive="active">{{library.name}}</a>
|
||||
@ -47,6 +47,6 @@
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<main id="main">
|
||||
<router-outlet></router-outlet>
|
||||
</main>
|
||||
|
@ -1,6 +1,12 @@
|
||||
@import "~bootstrap/scss/functions";
|
||||
@import "~bootstrap/scss/variables";
|
||||
@import "~bootstrap/scss/mixins/breakpoints";
|
||||
@import "variables";
|
||||
|
||||
#toolbar
|
||||
{
|
||||
height: $nav-bar-height;
|
||||
}
|
||||
|
||||
.navbar
|
||||
{
|
||||
@ -111,29 +117,27 @@ input::-webkit-search-cancel-button
|
||||
|
||||
main
|
||||
{
|
||||
max-height: calc(100vh - 68px) !important;
|
||||
margin-top: $nav-bar-height;
|
||||
padding-top: 4px;
|
||||
max-height: calc(100vh - #{$nav-bar-height});
|
||||
display: block;
|
||||
overflow-y: auto;
|
||||
scrollbar-color: #999 transparent;
|
||||
position: relative;
|
||||
|
||||
&:last-child
|
||||
&::-webkit-scrollbar
|
||||
{
|
||||
display: block;
|
||||
overflow-y: auto;
|
||||
width: 8px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
scrollbar-color: #999 transparent;
|
||||
&::-webkit-scrollbar-thumb
|
||||
{
|
||||
background-color: #999;
|
||||
|
||||
&::-webkit-scrollbar
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
width: 8px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb
|
||||
{
|
||||
background-color: #999;
|
||||
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
background-color: rgb(134, 127, 127);
|
||||
}
|
||||
background-color: rgb(134, 127, 127);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
@import "../../../../node_modules/bootstrap/scss/functions";
|
||||
@import "../../../../node_modules/bootstrap/scss/variables";
|
||||
@import "../../../../node_modules/bootstrap/scss/mixins/breakpoints";
|
||||
@import "~bootstrap/scss/functions";
|
||||
@import "~bootstrap/scss/variables";
|
||||
@import "~bootstrap/scss/mixins/breakpoints";
|
||||
|
||||
.root
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
@import "../../../../node_modules/bootstrap/scss/functions";
|
||||
@import "../../../../node_modules/bootstrap/scss/variables";
|
||||
@import "../../../../node_modules/bootstrap/scss/mixins/breakpoints";
|
||||
@import "~bootstrap/scss/functions";
|
||||
@import "~bootstrap/scss/variables";
|
||||
@import "~bootstrap/scss/mixins/breakpoints";
|
||||
|
||||
button
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
@import "../../../../node_modules/bootstrap/scss/functions";
|
||||
@import "../../../../node_modules/bootstrap/scss/variables";
|
||||
@import "../../../../node_modules/bootstrap/scss/mixins/breakpoints";
|
||||
@import "~bootstrap/scss/functions";
|
||||
@import "~bootstrap/scss/variables";
|
||||
@import "~bootstrap/scss/mixins/breakpoints";
|
||||
|
||||
.container
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
@import "../../../../node_modules/bootstrap/scss/functions";
|
||||
@import "../../../../node_modules/bootstrap/scss/variables";
|
||||
@import "../../../../node_modules/bootstrap/scss/mixins/breakpoints";
|
||||
@import "~bootstrap/scss/functions";
|
||||
@import "~bootstrap/scss/variables";
|
||||
@import "~bootstrap/scss/mixins/breakpoints";
|
||||
|
||||
.people-container
|
||||
{
|
||||
|
@ -53,10 +53,14 @@
|
||||
{{genre.name}}
|
||||
<mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
<input #genreInput placeholder="New genre..." [matChipInputFor]="genreList" (matChipInputTokenEnd)="addGenre($event)"
|
||||
<input #genreInput placeholder="New genre..."
|
||||
[formControl]="genreForm"
|
||||
[matChipInputFor]="genreList"
|
||||
(matChipInputTokenEnd)="addGenre($event); $event.input.value = null;"
|
||||
[matAutocomplete]="genreAuto" />
|
||||
<mat-autocomplete #genreAuto="matAutocomplete" (optionSelected)="autocompleteGenre($event)">
|
||||
<mat-option *ngFor="let genre of this.allGenres" [value]="genre">
|
||||
<mat-autocomplete #genreAuto="matAutocomplete"
|
||||
(optionSelected)="autocompleteGenre($event); genreInput.value = null;">
|
||||
<mat-option *ngFor="let genre of this.filteredGenres | async" [value]="genre">
|
||||
{{genre.name}}
|
||||
</mat-option>
|
||||
</mat-autocomplete>
|
||||
@ -73,8 +77,8 @@
|
||||
<input matInput [value]="this.show.studio?.name"
|
||||
(input)="this.show.studio = {id: 0, slug: null, name: $event.target.value};"
|
||||
[matAutocomplete]="studioAuto" name="studio">
|
||||
<mat-autocomplete #studioAuto="matAutocomplete" (optionSelected)="this.show.studio = $event.option.value">
|
||||
<mat-option *ngFor="let studio of this.allStudios" [value]="studio">
|
||||
<mat-autocomplete #studioAuto="matAutocomplete" (optionSelected)="this.show.studio = $event.option.value">
|
||||
<mat-option *ngFor="let studio of this.filteredStudios | async" [value]="studio">
|
||||
{{studio.name}}
|
||||
</mat-option>
|
||||
</mat-autocomplete>
|
||||
|
@ -1,6 +1,6 @@
|
||||
@import "../../../../node_modules/bootstrap/scss/functions";
|
||||
@import "../../../../node_modules/bootstrap/scss/variables";
|
||||
@import "../../../../node_modules/bootstrap/scss/mixins/breakpoints";
|
||||
@import "~bootstrap/scss/functions";
|
||||
@import "~bootstrap/scss/variables";
|
||||
@import "~bootstrap/scss/mixins/breakpoints";
|
||||
|
||||
.provider
|
||||
{
|
||||
@ -15,4 +15,4 @@
|
||||
{
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,53 +1,84 @@
|
||||
import {Component, ElementRef, Inject, ViewChild} from '@angular/core';
|
||||
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {Show} from "../../models/resources/show";
|
||||
import {Genre} from "../../models/resources/genre";
|
||||
import {MatChipInputEvent} from "@angular/material/chips";
|
||||
import {MatAutocompleteSelectedEvent} from "@angular/material/autocomplete";
|
||||
import {Observable, of} from "rxjs";
|
||||
import {tap} from "rxjs/operators";
|
||||
import {Studio} from "../../models/resources/studio";
|
||||
import {Provider} from "../../models/provider";
|
||||
import {MatSnackBar} from "@angular/material/snack-bar";
|
||||
import {ShowGridComponent} from "../../components/show-grid/show-grid.component";
|
||||
import { Component, Inject, OnInit, ViewChild } from "@angular/core";
|
||||
import { FormControl } from "@angular/forms";
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog";
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
import { Page } from "../../models/page";
|
||||
import { Show } from "../../models/resources/show";
|
||||
import { Genre } from "../../models/resources/genre";
|
||||
import { MatChipInputEvent } from "@angular/material/chips";
|
||||
import { MatAutocompleteSelectedEvent } from "@angular/material/autocomplete";
|
||||
import { Observable, of} from "rxjs";
|
||||
import { catchError, filter, map, mergeAll, tap } from "rxjs/operators";
|
||||
import { Studio } from "../../models/resources/studio";
|
||||
import { Provider } from "../../models/provider";
|
||||
import { MatSnackBar } from "@angular/material/snack-bar";
|
||||
import { ShowGridComponent } from "../../components/show-grid/show-grid.component";
|
||||
import { GenreService, StudioService } from "../../services/api.service";
|
||||
|
||||
@Component({
|
||||
selector: 'app-metadata-edit',
|
||||
templateUrl: './metadata-edit.component.html',
|
||||
styleUrls: ['./metadata-edit.component.scss']
|
||||
})
|
||||
export class MetadataEditComponent
|
||||
export class MetadataEditComponent implements OnInit
|
||||
{
|
||||
@ViewChild("genreInput") private genreInput: ElementRef<HTMLInputElement>;
|
||||
public allGenres: Genre[];
|
||||
public allStudios: Studio[];
|
||||
studioForm: FormControl = new FormControl();
|
||||
filteredStudios: Observable<Studio[]>;
|
||||
|
||||
genreForm: FormControl = new FormControl();
|
||||
filteredGenres: Observable<Genre[]>;
|
||||
|
||||
@ViewChild("identifyGrid") private identifyGrid: ShowGridComponent;
|
||||
private identifying: Observable<Show[]>;
|
||||
private identifiedShows: [string, Show[]];
|
||||
public providers: Provider[];
|
||||
public providers: Provider[] = [];
|
||||
|
||||
public metadataChanged: boolean = false;
|
||||
|
||||
constructor(public dialogRef: MatDialogRef<MetadataEditComponent>, @Inject(MAT_DIALOG_DATA) public show: Show, private http: HttpClient, private snackBar: MatSnackBar)
|
||||
constructor(public dialogRef: MatDialogRef<MetadataEditComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public show: Show,
|
||||
private http: HttpClient,
|
||||
private studioApi: StudioService,
|
||||
private genreApi: GenreService,
|
||||
private snackBar: MatSnackBar)
|
||||
{
|
||||
this.http.get<Genre[]>("/api/genres").subscribe(result =>
|
||||
this.http.get<Page<Provider>>("/api/providers").subscribe(result =>
|
||||
{
|
||||
this.allGenres = result;
|
||||
});
|
||||
this.http.get<Studio[]>("/api/studios").subscribe(result =>
|
||||
{
|
||||
this.allStudios = result;
|
||||
});
|
||||
this.http.get<Provider[]>("/api/providers").subscribe(result =>
|
||||
{
|
||||
this.providers = result;
|
||||
this.providers = result.items;
|
||||
});
|
||||
|
||||
this.reIdentify(this.show.title);
|
||||
}
|
||||
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
this.filteredGenres = this.genreForm.valueChanges
|
||||
.pipe(
|
||||
filter(x => x),
|
||||
map(x => typeof x === "string" ? x : x.name),
|
||||
map(x => this.genreApi.search(x)),
|
||||
mergeAll(),
|
||||
catchError(x =>
|
||||
{
|
||||
console.log(x);
|
||||
return [];
|
||||
})
|
||||
);
|
||||
|
||||
this.filteredStudios = this.studioForm.valueChanges
|
||||
.pipe(
|
||||
filter(x => x),
|
||||
map(x => typeof x === "string" ? x : x.name),
|
||||
map(x => this.studioApi.search(x)),
|
||||
mergeAll(),
|
||||
catchError(x =>
|
||||
{
|
||||
console.log(x);
|
||||
return [];
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
apply(): void
|
||||
{
|
||||
if (this.metadataChanged)
|
||||
@ -59,7 +90,7 @@ export class MetadataEditComponent
|
||||
},
|
||||
() =>
|
||||
{
|
||||
this.snackBar.open("An unknown error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
this.snackBar.open("An unknown error occurred.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
}
|
||||
);
|
||||
this.dialogRef.close(this.show);
|
||||
@ -106,10 +137,9 @@ export class MetadataEditComponent
|
||||
this.show.genres.splice(i, 1);
|
||||
}
|
||||
|
||||
autocompleteGenre(event: MatAutocompleteSelectedEvent): void
|
||||
autocompleteGenre(event: MatAutocompleteSelectedEvent): void
|
||||
{
|
||||
this.show.genres.push(event.option.value);
|
||||
this.genreInput.nativeElement.value = '';
|
||||
}
|
||||
|
||||
identityShow(name: string): Observable<Show[]>
|
||||
|
@ -1,6 +1,7 @@
|
||||
@import "../../../../node_modules/bootstrap/scss/functions";
|
||||
@import "../../../../node_modules/bootstrap/scss/variables";
|
||||
@import "../../../../node_modules/bootstrap/scss/mixins/breakpoints";
|
||||
@import "~bootstrap/scss/functions";
|
||||
@import "~bootstrap/scss/variables";
|
||||
@import "~bootstrap/scss/mixins/breakpoints";
|
||||
@import "variables";
|
||||
|
||||
a
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, HostListener, OnInit } from "@angular/core";
|
||||
import { AfterViewInit, Component, HostListener, OnInit } from "@angular/core";
|
||||
import { MatSnackBar } from "@angular/material/snack-bar";
|
||||
import { DomSanitizer, Title } from "@angular/platform-browser";
|
||||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
@ -17,7 +17,7 @@ import {People} from "../../models/resources/people";
|
||||
templateUrl: './show-details.component.html',
|
||||
styleUrls: ['./show-details.component.scss']
|
||||
})
|
||||
export class ShowDetailsComponent implements OnInit
|
||||
export class ShowDetailsComponent implements AfterViewInit
|
||||
{
|
||||
show: Show;
|
||||
seasons: Season[];
|
||||
@ -25,6 +25,7 @@ export class ShowDetailsComponent implements OnInit
|
||||
episodes: Page<Episode>[] = [];
|
||||
people: Page<People>;
|
||||
|
||||
private scrollZone: HTMLElement;
|
||||
private toolbar: HTMLElement;
|
||||
private backdrop: HTMLElement;
|
||||
|
||||
@ -65,23 +66,30 @@ export class ShowDetailsComponent implements OnInit
|
||||
this.getEpisodes(this.season);});
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
ngAfterViewInit()
|
||||
{
|
||||
this.scrollZone = document.getElementById("main");
|
||||
this.toolbar = document.getElementById("toolbar");
|
||||
this.backdrop = document.getElementById("backdrop");
|
||||
this.toolbar.setAttribute("style", `background-color: rgba(0, 0, 0, 0) !important`);
|
||||
this.scrollZone.style.marginTop = "0";
|
||||
this.scrollZone.style.maxHeight = "100vh";
|
||||
this.scrollZone.addEventListener("scroll", () => this.scroll());
|
||||
}
|
||||
|
||||
ngOnDestroy()
|
||||
{
|
||||
this.title.setTitle("Kyoo");
|
||||
this.toolbar.setAttribute("style", `background-color: #000000 !important`);
|
||||
this.scrollZone.style.marginTop = null;
|
||||
this.scrollZone.style.maxHeight = null;
|
||||
this.scrollZone.removeEventListener("scroll", () => this.scroll());
|
||||
}
|
||||
|
||||
@HostListener("window:scroll")
|
||||
scroll()
|
||||
{
|
||||
let opacity: number = 2 * window.scrollY / this.backdrop.clientHeight;
|
||||
console.log("scroll");
|
||||
let opacity: number = 2 * this.scrollZone.scrollTop / this.backdrop.clientHeight;
|
||||
this.toolbar.setAttribute("style", `background-color: rgba(0, 0, 0, ${opacity}) !important`);
|
||||
};
|
||||
|
||||
|
@ -2,6 +2,7 @@ import {Injectable} from "@angular/core";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {Observable} from "rxjs"
|
||||
import {Page} from "../models/page";
|
||||
import { Genre } from "../models/resources/genre";
|
||||
import {IResource} from "../models/resources/resource";
|
||||
import {Library} from "../models/resources/library";
|
||||
import {LibraryItem} from "../models/resources/library-item";
|
||||
@ -144,6 +145,23 @@ export class PeopleService extends CrudApi<People>
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class GenreService extends CrudApi<Genre>
|
||||
{
|
||||
constructor(client: HttpClient)
|
||||
{
|
||||
super(client, "genres");
|
||||
}
|
||||
|
||||
getFromShow(show: string | number, args?: ApiArgs): Observable<Page<Genre>>
|
||||
{
|
||||
return this.client.get<Page<Genre>>(`/api/shows/${show}/genres${this.ArgsAsQuery(args)}`)
|
||||
.pipe(map(x => Object.assign(new Page<Genre>(), x)));
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
|
1
src/variables.scss
Normal file
1
src/variables.scss
Normal file
@ -0,0 +1 @@
|
||||
$nav-bar-height: 64px;
|
Loading…
x
Reference in New Issue
Block a user