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/jquery/dist/jquery.min.js",
|
||||||
"./node_modules/bootstrap/dist/js/bootstrap.bundle.min.js",
|
"./node_modules/bootstrap/dist/js/bootstrap.bundle.min.js",
|
||||||
"./node_modules/hls.js/dist/hls.js"
|
"./node_modules/hls.js/dist/hls.js"
|
||||||
]
|
],
|
||||||
|
"stylePreprocessorOptions": {
|
||||||
|
"includePaths": ["src"]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<header id="nav" style="height: 68px;">
|
<header id="nav">
|
||||||
<div class="fixed-top">
|
<div class="fixed-top">
|
||||||
<nav id="toolbar" class="navbar navbar-dark bg-secondary">
|
<nav id="toolbar" class="navbar navbar-dark bg-secondary">
|
||||||
<a class="navbar-brand nav-item ml-3" routerLink="/">
|
<a class="navbar-brand nav-item ml-3" routerLink="/">
|
||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
<ul class="navbar-nav flex-row">
|
<ul class="navbar-nav flex-row">
|
||||||
<li class="nav-item">
|
<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>
|
||||||
<li class="nav-item" *ngFor="let library of this.libraries">
|
<li class="nav-item" *ngFor="let library of this.libraries">
|
||||||
<a class="nav-link" routerLink="/browse/{{library.slug}}" routerLinkActive="active">{{library.name}}</a>
|
<a class="nav-link" routerLink="/browse/{{library.slug}}" routerLinkActive="active">{{library.name}}</a>
|
||||||
@ -47,6 +47,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main>
|
<main id="main">
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
</main>
|
</main>
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
@import "~bootstrap/scss/functions";
|
@import "~bootstrap/scss/functions";
|
||||||
@import "~bootstrap/scss/variables";
|
@import "~bootstrap/scss/variables";
|
||||||
@import "~bootstrap/scss/mixins/breakpoints";
|
@import "~bootstrap/scss/mixins/breakpoints";
|
||||||
|
@import "variables";
|
||||||
|
|
||||||
|
#toolbar
|
||||||
|
{
|
||||||
|
height: $nav-bar-height;
|
||||||
|
}
|
||||||
|
|
||||||
.navbar
|
.navbar
|
||||||
{
|
{
|
||||||
@ -111,14 +117,13 @@ input::-webkit-search-cancel-button
|
|||||||
|
|
||||||
main
|
main
|
||||||
{
|
{
|
||||||
max-height: calc(100vh - 68px) !important;
|
margin-top: $nav-bar-height;
|
||||||
|
padding-top: 4px;
|
||||||
&:last-child
|
max-height: calc(100vh - #{$nav-bar-height});
|
||||||
{
|
|
||||||
display: block;
|
display: block;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
||||||
scrollbar-color: #999 transparent;
|
scrollbar-color: #999 transparent;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
&::-webkit-scrollbar
|
&::-webkit-scrollbar
|
||||||
{
|
{
|
||||||
@ -135,5 +140,4 @@ main
|
|||||||
background-color: rgb(134, 127, 127);
|
background-color: rgb(134, 127, 127);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
@import "../../../../node_modules/bootstrap/scss/functions";
|
@import "~bootstrap/scss/functions";
|
||||||
@import "../../../../node_modules/bootstrap/scss/variables";
|
@import "~bootstrap/scss/variables";
|
||||||
@import "../../../../node_modules/bootstrap/scss/mixins/breakpoints";
|
@import "~bootstrap/scss/mixins/breakpoints";
|
||||||
|
|
||||||
.root
|
.root
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
@import "../../../../node_modules/bootstrap/scss/functions";
|
@import "~bootstrap/scss/functions";
|
||||||
@import "../../../../node_modules/bootstrap/scss/variables";
|
@import "~bootstrap/scss/variables";
|
||||||
@import "../../../../node_modules/bootstrap/scss/mixins/breakpoints";
|
@import "~bootstrap/scss/mixins/breakpoints";
|
||||||
|
|
||||||
button
|
button
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
@import "../../../../node_modules/bootstrap/scss/functions";
|
@import "~bootstrap/scss/functions";
|
||||||
@import "../../../../node_modules/bootstrap/scss/variables";
|
@import "~bootstrap/scss/variables";
|
||||||
@import "../../../../node_modules/bootstrap/scss/mixins/breakpoints";
|
@import "~bootstrap/scss/mixins/breakpoints";
|
||||||
|
|
||||||
.container
|
.container
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
@import "../../../../node_modules/bootstrap/scss/functions";
|
@import "~bootstrap/scss/functions";
|
||||||
@import "../../../../node_modules/bootstrap/scss/variables";
|
@import "~bootstrap/scss/variables";
|
||||||
@import "../../../../node_modules/bootstrap/scss/mixins/breakpoints";
|
@import "~bootstrap/scss/mixins/breakpoints";
|
||||||
|
|
||||||
.people-container
|
.people-container
|
||||||
{
|
{
|
||||||
|
@ -53,10 +53,14 @@
|
|||||||
{{genre.name}}
|
{{genre.name}}
|
||||||
<mat-icon matChipRemove>cancel</mat-icon>
|
<mat-icon matChipRemove>cancel</mat-icon>
|
||||||
</mat-chip>
|
</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" />
|
[matAutocomplete]="genreAuto" />
|
||||||
<mat-autocomplete #genreAuto="matAutocomplete" (optionSelected)="autocompleteGenre($event)">
|
<mat-autocomplete #genreAuto="matAutocomplete"
|
||||||
<mat-option *ngFor="let genre of this.allGenres" [value]="genre">
|
(optionSelected)="autocompleteGenre($event); genreInput.value = null;">
|
||||||
|
<mat-option *ngFor="let genre of this.filteredGenres | async" [value]="genre">
|
||||||
{{genre.name}}
|
{{genre.name}}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-autocomplete>
|
</mat-autocomplete>
|
||||||
@ -74,7 +78,7 @@
|
|||||||
(input)="this.show.studio = {id: 0, slug: null, name: $event.target.value};"
|
(input)="this.show.studio = {id: 0, slug: null, name: $event.target.value};"
|
||||||
[matAutocomplete]="studioAuto" name="studio">
|
[matAutocomplete]="studioAuto" name="studio">
|
||||||
<mat-autocomplete #studioAuto="matAutocomplete" (optionSelected)="this.show.studio = $event.option.value">
|
<mat-autocomplete #studioAuto="matAutocomplete" (optionSelected)="this.show.studio = $event.option.value">
|
||||||
<mat-option *ngFor="let studio of this.allStudios" [value]="studio">
|
<mat-option *ngFor="let studio of this.filteredStudios | async" [value]="studio">
|
||||||
{{studio.name}}
|
{{studio.name}}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-autocomplete>
|
</mat-autocomplete>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
@import "../../../../node_modules/bootstrap/scss/functions";
|
@import "~bootstrap/scss/functions";
|
||||||
@import "../../../../node_modules/bootstrap/scss/variables";
|
@import "~bootstrap/scss/variables";
|
||||||
@import "../../../../node_modules/bootstrap/scss/mixins/breakpoints";
|
@import "~bootstrap/scss/mixins/breakpoints";
|
||||||
|
|
||||||
.provider
|
.provider
|
||||||
{
|
{
|
||||||
|
@ -1,53 +1,84 @@
|
|||||||
import {Component, ElementRef, Inject, ViewChild} from '@angular/core';
|
import { Component, Inject, OnInit, ViewChild } from "@angular/core";
|
||||||
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
import { FormControl } from "@angular/forms";
|
||||||
import {HttpClient} from "@angular/common/http";
|
import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog";
|
||||||
import {Show} from "../../models/resources/show";
|
import { HttpClient } from "@angular/common/http";
|
||||||
import {Genre} from "../../models/resources/genre";
|
import { Page } from "../../models/page";
|
||||||
import {MatChipInputEvent} from "@angular/material/chips";
|
import { Show } from "../../models/resources/show";
|
||||||
import {MatAutocompleteSelectedEvent} from "@angular/material/autocomplete";
|
import { Genre } from "../../models/resources/genre";
|
||||||
import {Observable, of} from "rxjs";
|
import { MatChipInputEvent } from "@angular/material/chips";
|
||||||
import {tap} from "rxjs/operators";
|
import { MatAutocompleteSelectedEvent } from "@angular/material/autocomplete";
|
||||||
import {Studio} from "../../models/resources/studio";
|
import { Observable, of} from "rxjs";
|
||||||
import {Provider} from "../../models/provider";
|
import { catchError, filter, map, mergeAll, tap } from "rxjs/operators";
|
||||||
import {MatSnackBar} from "@angular/material/snack-bar";
|
import { Studio } from "../../models/resources/studio";
|
||||||
import {ShowGridComponent} from "../../components/show-grid/show-grid.component";
|
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({
|
@Component({
|
||||||
selector: 'app-metadata-edit',
|
selector: 'app-metadata-edit',
|
||||||
templateUrl: './metadata-edit.component.html',
|
templateUrl: './metadata-edit.component.html',
|
||||||
styleUrls: ['./metadata-edit.component.scss']
|
styleUrls: ['./metadata-edit.component.scss']
|
||||||
})
|
})
|
||||||
export class MetadataEditComponent
|
export class MetadataEditComponent implements OnInit
|
||||||
{
|
{
|
||||||
@ViewChild("genreInput") private genreInput: ElementRef<HTMLInputElement>;
|
studioForm: FormControl = new FormControl();
|
||||||
public allGenres: Genre[];
|
filteredStudios: Observable<Studio[]>;
|
||||||
public allStudios: Studio[];
|
|
||||||
|
genreForm: FormControl = new FormControl();
|
||||||
|
filteredGenres: Observable<Genre[]>;
|
||||||
|
|
||||||
@ViewChild("identifyGrid") private identifyGrid: ShowGridComponent;
|
@ViewChild("identifyGrid") private identifyGrid: ShowGridComponent;
|
||||||
private identifying: Observable<Show[]>;
|
private identifying: Observable<Show[]>;
|
||||||
private identifiedShows: [string, Show[]];
|
private identifiedShows: [string, Show[]];
|
||||||
public providers: Provider[];
|
public providers: Provider[] = [];
|
||||||
|
|
||||||
public metadataChanged: boolean = false;
|
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.providers = result.items;
|
||||||
});
|
|
||||||
this.http.get<Studio[]>("/api/studios").subscribe(result =>
|
|
||||||
{
|
|
||||||
this.allStudios = result;
|
|
||||||
});
|
|
||||||
this.http.get<Provider[]>("/api/providers").subscribe(result =>
|
|
||||||
{
|
|
||||||
this.providers = result;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.reIdentify(this.show.title);
|
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
|
apply(): void
|
||||||
{
|
{
|
||||||
if (this.metadataChanged)
|
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);
|
this.dialogRef.close(this.show);
|
||||||
@ -109,7 +140,6 @@ export class MetadataEditComponent
|
|||||||
autocompleteGenre(event: MatAutocompleteSelectedEvent): void
|
autocompleteGenre(event: MatAutocompleteSelectedEvent): void
|
||||||
{
|
{
|
||||||
this.show.genres.push(event.option.value);
|
this.show.genres.push(event.option.value);
|
||||||
this.genreInput.nativeElement.value = '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
identityShow(name: string): Observable<Show[]>
|
identityShow(name: string): Observable<Show[]>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
@import "../../../../node_modules/bootstrap/scss/functions";
|
@import "~bootstrap/scss/functions";
|
||||||
@import "../../../../node_modules/bootstrap/scss/variables";
|
@import "~bootstrap/scss/variables";
|
||||||
@import "../../../../node_modules/bootstrap/scss/mixins/breakpoints";
|
@import "~bootstrap/scss/mixins/breakpoints";
|
||||||
|
@import "variables";
|
||||||
|
|
||||||
a
|
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 { MatSnackBar } from "@angular/material/snack-bar";
|
||||||
import { DomSanitizer, Title } from "@angular/platform-browser";
|
import { DomSanitizer, Title } from "@angular/platform-browser";
|
||||||
import {ActivatedRoute, Router} from '@angular/router';
|
import {ActivatedRoute, Router} from '@angular/router';
|
||||||
@ -17,7 +17,7 @@ import {People} from "../../models/resources/people";
|
|||||||
templateUrl: './show-details.component.html',
|
templateUrl: './show-details.component.html',
|
||||||
styleUrls: ['./show-details.component.scss']
|
styleUrls: ['./show-details.component.scss']
|
||||||
})
|
})
|
||||||
export class ShowDetailsComponent implements OnInit
|
export class ShowDetailsComponent implements AfterViewInit
|
||||||
{
|
{
|
||||||
show: Show;
|
show: Show;
|
||||||
seasons: Season[];
|
seasons: Season[];
|
||||||
@ -25,6 +25,7 @@ export class ShowDetailsComponent implements OnInit
|
|||||||
episodes: Page<Episode>[] = [];
|
episodes: Page<Episode>[] = [];
|
||||||
people: Page<People>;
|
people: Page<People>;
|
||||||
|
|
||||||
|
private scrollZone: HTMLElement;
|
||||||
private toolbar: HTMLElement;
|
private toolbar: HTMLElement;
|
||||||
private backdrop: HTMLElement;
|
private backdrop: HTMLElement;
|
||||||
|
|
||||||
@ -65,23 +66,30 @@ export class ShowDetailsComponent implements OnInit
|
|||||||
this.getEpisodes(this.season);});
|
this.getEpisodes(this.season);});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit()
|
ngAfterViewInit()
|
||||||
{
|
{
|
||||||
|
this.scrollZone = document.getElementById("main");
|
||||||
this.toolbar = document.getElementById("toolbar");
|
this.toolbar = document.getElementById("toolbar");
|
||||||
this.backdrop = document.getElementById("backdrop");
|
this.backdrop = document.getElementById("backdrop");
|
||||||
this.toolbar.setAttribute("style", `background-color: rgba(0, 0, 0, 0) !important`);
|
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()
|
ngOnDestroy()
|
||||||
{
|
{
|
||||||
this.title.setTitle("Kyoo");
|
this.title.setTitle("Kyoo");
|
||||||
this.toolbar.setAttribute("style", `background-color: #000000 !important`);
|
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()
|
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`);
|
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 {HttpClient} from "@angular/common/http";
|
||||||
import {Observable} from "rxjs"
|
import {Observable} from "rxjs"
|
||||||
import {Page} from "../models/page";
|
import {Page} from "../models/page";
|
||||||
|
import { Genre } from "../models/resources/genre";
|
||||||
import {IResource} from "../models/resources/resource";
|
import {IResource} from "../models/resources/resource";
|
||||||
import {Library} from "../models/resources/library";
|
import {Library} from "../models/resources/library";
|
||||||
import {LibraryItem} from "../models/resources/library-item";
|
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({
|
@Injectable({
|
||||||
providedIn: 'root'
|
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