mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-15 08:15:37 +00:00
WIP: Implement frontend
Implemented 1st version of game-detail-view
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
<div class="game-cover-container">
|
||||
<a routerLink="/game/{{game.slug}}">
|
||||
<img src="{{'v1/images/' + game.coverId}}" alt="Cover of {{game.title}}">
|
||||
</a>
|
||||
</div>
|
||||
<a routerLink="/game/{{game.slug}}">
|
||||
<div class="game-cover-container shine" [style.background-image]="'url(v1/images/' + game.coverId + ')'">
|
||||
</div>
|
||||
</a>
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
@use '@angular/material' as mat;
|
||||
|
||||
.game-cover-container img {
|
||||
.game-cover-container {
|
||||
|
||||
height: 352px;
|
||||
width: 264px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center bottom;
|
||||
|
||||
@include mat.elevation-transition();
|
||||
@include mat.elevation(4);
|
||||
@@ -9,3 +14,38 @@
|
||||
@include mat.elevation(24);
|
||||
}
|
||||
}
|
||||
|
||||
.shine {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&::before {
|
||||
background: linear-gradient(
|
||||
to right,
|
||||
fade_out(#fff, 1) 0%,
|
||||
fade_out(#fff, 0.7) 100%
|
||||
);
|
||||
content: "";
|
||||
display: block;
|
||||
height: 100%;
|
||||
left: -100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
transform: skewX(-25deg);
|
||||
width: 50%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
&::before {
|
||||
animation: shine 0.85s;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shine {
|
||||
100% {
|
||||
left: 125%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
import {GameOverviewDto} from "../../models/dtos/GameOverviewDto";
|
||||
import {DetectedGameDto} from "../../models/dtos/DetectedGameDto";
|
||||
|
||||
@Component({
|
||||
selector: 'game-cover',
|
||||
@@ -8,7 +8,7 @@ import {GameOverviewDto} from "../../models/dtos/GameOverviewDto";
|
||||
})
|
||||
export class GameCoverComponent implements OnInit {
|
||||
|
||||
@Input() game!: GameOverviewDto;
|
||||
@Input() game!: DetectedGameDto;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
@@ -1 +1,28 @@
|
||||
<pre><code>{{game | json}}</code></pre>
|
||||
<div fxLayout="row" fxLayoutAlign="center" style="margin-top: 16px;">
|
||||
<div fxLayout="column" fxFlex="0 1 70" fxLayoutGap="16px" fxFlex.lt-xl="95">
|
||||
<div fxLayout="row" fxLayoutGap="16px" style="background: aqua">
|
||||
<img src="v1/images/{{game.coverId}}" alt="Game cover">
|
||||
<div fxFlex="30" fxLayout="column" id="game-details" style="background: darkolivegreen">
|
||||
<h2>{{game.title}}</h2>
|
||||
<p id="game-summary">{{game.summary}}</p>
|
||||
</div>
|
||||
<div fxLayout="column" fxFlex style="background: coral">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div fxLayout="column" fxLayoutGap="16px">
|
||||
<h2>Screenshots</h2>
|
||||
<div fxLayout="row wrap" fxLayoutGap="8px">
|
||||
<div *ngFor="let screenshotId of game.screenshotIds">
|
||||
<game-screenshot [screenshotId]="screenshotId"></game-screenshot>
|
||||
</div>
|
||||
</div>
|
||||
<h2>Videos</h2>
|
||||
<div fxLayout="row wrap" fxLayoutGap="8px">
|
||||
<div *ngFor="let videoId of game.videoIds">
|
||||
<game-video [videoId]="videoId" [width]="555" [height]="312"></game-video>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<img src="v1/images/{{screenshotId}}" alt="Screenshot">
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GameScreenshotComponent } from './game-screenshot.component';
|
||||
|
||||
describe('GameScreenshotComponent', () => {
|
||||
let component: GameScreenshotComponent;
|
||||
let fixture: ComponentFixture<GameScreenshotComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ GameScreenshotComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(GameScreenshotComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'game-screenshot',
|
||||
templateUrl: './game-screenshot.component.html',
|
||||
styleUrls: ['./game-screenshot.component.scss']
|
||||
})
|
||||
export class GameScreenshotComponent implements OnInit {
|
||||
|
||||
@Input() screenshotId!: string;
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<youtube-player [videoId]="videoId" [width]="width" [height]="height"></youtube-player>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GameVideoComponent } from './game-video.component';
|
||||
|
||||
describe('GameVideoComponent', () => {
|
||||
let component: GameVideoComponent;
|
||||
let fixture: ComponentFixture<GameVideoComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ GameVideoComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(GameVideoComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'game-video',
|
||||
templateUrl: './game-video.component.html',
|
||||
styleUrls: ['./game-video.component.scss']
|
||||
})
|
||||
export class GameVideoComponent implements OnInit {
|
||||
|
||||
@Input() videoId!: string;
|
||||
@Input() height!: number;
|
||||
@Input() width!: number;
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
const tag = document.createElement('script');
|
||||
tag.src = 'https://www.youtube.com/iframe_api';
|
||||
document.body.appendChild(tag);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
<mat-toolbar role="heading">
|
||||
<mat-toolbar style="position: sticky; top: 0; z-index: 99999">
|
||||
<button mat-icon-button (click)="goToLibraryScreen()" *ngIf="notOnLibraryScreen()">
|
||||
<mat-icon>home</mat-icon>
|
||||
</button>
|
||||
|
||||
<span class="spacer"></span>
|
||||
|
||||
|
||||
@@ -1,29 +1,34 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {NavMenuItem} from '../../models/objects/NavMenuItem';
|
||||
import {Component} from '@angular/core';
|
||||
import {LibraryService} from "../../services/library.service";
|
||||
import {MatSnackBar} from '@angular/material/snack-bar';
|
||||
import {timeInterval} from "rxjs";
|
||||
import {ActivatedRoute, Router} from "@angular/router";
|
||||
|
||||
@Component({
|
||||
selector: 'app-header',
|
||||
templateUrl: './header.component.html',
|
||||
styleUrls: ['./header.component.scss']
|
||||
})
|
||||
export class HeaderComponent implements OnInit {
|
||||
|
||||
activeItem: NavMenuItem | undefined;
|
||||
export class HeaderComponent {
|
||||
|
||||
constructor(private libraryService: LibraryService,
|
||||
private snackBar: MatSnackBar) {
|
||||
private snackBar: MatSnackBar,
|
||||
private router: Router) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
reloadLibrary() {
|
||||
reloadLibrary(): void {
|
||||
this.libraryService.scanLibrary().pipe(timeInterval()).subscribe({
|
||||
next: value => this.snackBar.open(`Library scan completed in ${Math.trunc(value.interval/1000)} seconds.`),
|
||||
next: value => this.snackBar.open(`Library scan completed in ${Math.trunc(value.interval / 1000)} seconds.`),
|
||||
error: error => this.snackBar.open(`Error while scanning library: ${error}`)
|
||||
})
|
||||
}
|
||||
|
||||
goToLibraryScreen(): void {
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
|
||||
notOnLibraryScreen(): boolean {
|
||||
return !(this.router.url === "/library");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,12 +14,3 @@
|
||||
.content {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.content > mat-card {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.column-label {
|
||||
margin-right: 8px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
@@ -8,11 +8,14 @@
|
||||
<h2>Your game library is empty!</h2>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div fxLayout="row wrap" fxLayoutGap="16px grid">
|
||||
<div fxFlex="25% 1" fxFlex.xs="100%" fxFlex.sm="33%" *ngFor="let game of detectedGames">
|
||||
<div class="content" fxLayout="row" fxFlexFill="100" *ngIf="!this.loading && this.detectedGames.length > 0">
|
||||
<div fxFlex="10" fxHide fxShow.gt-md><!--SPACER--></div>
|
||||
<div fxFlex="0 1 20"><!--FILTER--></div>
|
||||
<div fxFlex fxLayout="row wrap" fxLayoutGap="16px grid">
|
||||
<div *ngFor="let game of detectedGames">
|
||||
<game-cover [game]="game"></game-cover>
|
||||
</div>
|
||||
</div>
|
||||
<div fxFlex="0 1 10" fxHide fxShow.gt-lg><!--SPACER--></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {AfterViewInit, Component} from '@angular/core';
|
||||
import {GamesService} from "../../services/games.service";
|
||||
import {DetectedGameDto} from "../../models/dtos/DetectedGameDto";
|
||||
import {GameOverviewDto} from "../../models/dtos/GameOverviewDto";
|
||||
|
||||
@Component({
|
||||
selector: 'app-gameserver-list',
|
||||
@@ -10,15 +9,15 @@ import {GameOverviewDto} from "../../models/dtos/GameOverviewDto";
|
||||
})
|
||||
export class LibraryOverviewComponent implements AfterViewInit {
|
||||
|
||||
detectedGames: GameOverviewDto[] = [];
|
||||
detectedGames: DetectedGameDto[] = [];
|
||||
loading: boolean = true;
|
||||
|
||||
constructor(private gameServerService: GamesService) {
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.gameServerService.getGameOverviews().subscribe(
|
||||
(detectedGames: GameOverviewDto[]) => {
|
||||
this.gameServerService.getAllGames().subscribe(
|
||||
(detectedGames: DetectedGameDto[]) => {
|
||||
this.detectedGames = detectedGames;
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user