refine list
This commit is contained in:
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -9,7 +9,7 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Launch Chrome against localhost",
|
"name": "Launch Chrome against localhost",
|
||||||
"url": "http://localhost:4200",
|
"url": "http://localhost:4200",
|
||||||
"webRoot": "${workspaceFolder}"
|
"webRoot": "${workspaceFolder}/WEB"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
15
WEB/.vscode/launch.json
vendored
Normal file
15
WEB/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "chrome",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch Chrome against localhost",
|
||||||
|
"url": "http://localhost:4200",
|
||||||
|
"webRoot": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,24 +1,11 @@
|
|||||||
import { SongsComponent } from './components/songs/songs.component';
|
import { SongsComponent } from './components/songs/songs.component';
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { Routes, RouterModule } from '@angular/router';
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
import { SongsResolverService } from './data/songs-resolver.service';
|
|
||||||
import { SongComponent } from './components/song/song.component';
|
|
||||||
import { SongResolverService } from './data/song-resolver.service';
|
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: 'songs',
|
path: 'songs',
|
||||||
component: SongsComponent,
|
component: SongsComponent
|
||||||
resolve: {
|
|
||||||
songs: SongsResolverService
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'songs/:id',
|
|
||||||
component: SongComponent,
|
|
||||||
resolve: {
|
|
||||||
song: SongResolverService
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
|
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
|
<router-outlet name="detail"></router-outlet>
|
||||||
|
|||||||
@@ -5,6 +5,4 @@ import { Component } from '@angular/core';
|
|||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrls: ['./app.component.less']
|
styleUrls: ['./app.component.less']
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent { }
|
||||||
title = 'wgenerator';
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { ODataModule } from 'odata-v4-ng';
|
import { ODataModule } from 'odata-v4-ng';
|
||||||
|
|
||||||
@@ -10,15 +11,17 @@ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
|||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import { MatCardModule } from '@angular/material/card';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatChipsModule } from '@angular/material/chips';
|
||||||
|
|
||||||
import { TableComponent } from './components/songs/table/table.component';
|
import { TableComponent } from './components/songs/table/table.component';
|
||||||
import { SongsComponent } from './components/songs/songs.component';
|
import { SongsComponent } from './components/songs/songs.component';
|
||||||
import { SongComponent } from './components/song/song.component';
|
import { SongComponent } from './components/songs/song/song.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [AppComponent, SongsComponent, TableComponent, SongComponent],
|
declarations: [AppComponent, SongsComponent, TableComponent, SongComponent],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
BrowserAnimationsModule,
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
ODataModule,
|
ODataModule,
|
||||||
@@ -26,6 +29,7 @@ import { SongComponent } from './components/song/song.component';
|
|||||||
MatCardModule,
|
MatCardModule,
|
||||||
MatTableModule,
|
MatTableModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
|
MatChipsModule,
|
||||||
|
|
||||||
FontAwesomeModule
|
FontAwesomeModule
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
<mat-card class="mat-elevation-z8">
|
|
||||||
<mat-card-header>
|
|
||||||
<div mat-card-avatar>
|
|
||||||
<button mat-icon-button [routerLink]="['/songs']" >
|
|
||||||
<fa-icon [icon]="faArrow"></fa-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<mat-card-title>{{ song.Name }}</mat-card-title>
|
|
||||||
<mat-card-subtitle>{{ song.Key }} - {{ song.Tempo }}</mat-card-subtitle>
|
|
||||||
</mat-card-header>
|
|
||||||
<mat-card-content>
|
|
||||||
<p *ngFor="let line of text">{{ line }}</p>
|
|
||||||
</mat-card-content>
|
|
||||||
<mat-card-actions>
|
|
||||||
<button mat-button (click)="onClickDownload()">Herunterladen</button>
|
|
||||||
</mat-card-actions>
|
|
||||||
</mat-card>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { SongComponent } from './song.component';
|
|
||||||
|
|
||||||
describe('SongComponent', () => {
|
|
||||||
let component: SongComponent;
|
|
||||||
let fixture: ComponentFixture<SongComponent>;
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [ SongComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(SongComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import { DownloadService } from "./../../data/download.service";
|
|
||||||
import { Component, OnInit } from "@angular/core";
|
|
||||||
import { ActivatedRoute } from "@angular/router";
|
|
||||||
import { faLongArrowAltLeft } from "@fortawesome/free-solid-svg-icons";
|
|
||||||
import { Song } from "src/app/models/song.model";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "app-song",
|
|
||||||
templateUrl: "./song.component.html",
|
|
||||||
styleUrls: ["./song.component.less"]
|
|
||||||
})
|
|
||||||
export class SongComponent implements OnInit {
|
|
||||||
public song: Song;
|
|
||||||
public faArrow = faLongArrowAltLeft;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private route: ActivatedRoute,
|
|
||||||
private downloadService: DownloadService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.route.data.subscribe((data: { song: Song }) => {
|
|
||||||
this.song = data.song;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public onClickDownload(): void {
|
|
||||||
const id = this.song.ID;
|
|
||||||
this.downloadService.get(id, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get text(): string[] {
|
|
||||||
return this.song.Text.split(/\r?\n/).filter(_ => _ !== ' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
19
WEB/src/app/components/songs/song/song.component.html
Normal file
19
WEB/src/app/components/songs/song/song.component.html
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<div class="song-detail-container">
|
||||||
|
<mat-card class="mat-elevation-z8" [@blend] *ngIf="selectedSongId !== 0">
|
||||||
|
<mat-card-header>
|
||||||
|
<div mat-card-avatar>
|
||||||
|
<button mat-icon-button (click)="onBack()">
|
||||||
|
<fa-icon [icon]="faArrow"></fa-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<mat-card-title>{{ song.Name }}</mat-card-title>
|
||||||
|
<mat-card-subtitle>{{ song.Key }} - {{ song.Tempo }}</mat-card-subtitle>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<p *ngFor="let line of text">{{ line }}</p>
|
||||||
|
</mat-card-content>
|
||||||
|
<mat-card-actions>
|
||||||
|
<button mat-button (click)="onClickDownload()">Herunterladen</button>
|
||||||
|
</mat-card-actions>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
@@ -1,15 +1,22 @@
|
|||||||
.mat-card {
|
.mat-card {
|
||||||
width: 500px;
|
width: 500px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
background: #fffe;
|
||||||
|
margin: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-card-title {
|
.mat-card-title {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
width: 450px;
|
width: 420px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-card-content {
|
.mat-card-content {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.song-detail-container {
|
||||||
|
margin-left: 30vw;
|
||||||
|
}
|
||||||
64
WEB/src/app/components/songs/song/song.component.ts
Normal file
64
WEB/src/app/components/songs/song/song.component.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import { SongsService } from 'src/app/data/songs.service';
|
||||||
|
import {
|
||||||
|
Component,
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
ChangeDetectorRef
|
||||||
|
} from '@angular/core';
|
||||||
|
import { faLongArrowAltLeft } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { Song } from 'src/app/models/song.model';
|
||||||
|
import { DownloadService } from 'src/app/data/download.service';
|
||||||
|
import { trigger, transition, style, animate } from '@angular/animations';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-song',
|
||||||
|
templateUrl: './song.component.html',
|
||||||
|
styleUrls: ['./song.component.less'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
animations: [
|
||||||
|
trigger('blend', [
|
||||||
|
transition(':enter', [
|
||||||
|
style({ opacity: 0 }),
|
||||||
|
animate('700ms', style({ opacity: 0 })),
|
||||||
|
animate('300ms', style({ opacity: 1 }))
|
||||||
|
]),
|
||||||
|
transition(':leave', [
|
||||||
|
style({ opacity: 1 }),
|
||||||
|
animate('300ms', style({ opacity: 0 }))
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class SongComponent {
|
||||||
|
public song: Song;
|
||||||
|
public faArrow = faLongArrowAltLeft;
|
||||||
|
public selectedSongId = 0;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private songService: SongsService,
|
||||||
|
private downloadService: DownloadService,
|
||||||
|
change: ChangeDetectorRef
|
||||||
|
) {
|
||||||
|
songService.selectedSong.subscribe(_ => {
|
||||||
|
if (_) {
|
||||||
|
this.selectedSongId = _.ID;
|
||||||
|
this.song = _;
|
||||||
|
} else {
|
||||||
|
this.selectedSongId = 0;
|
||||||
|
this.song = null;
|
||||||
|
}
|
||||||
|
change.markForCheck();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public onBack(): void {
|
||||||
|
this.songService.resetSelectedSong();
|
||||||
|
}
|
||||||
|
|
||||||
|
public onClickDownload(): void {
|
||||||
|
const id = this.song.ID;
|
||||||
|
this.downloadService.get(id, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get text(): string[] {
|
||||||
|
return this.song.Text.split(/\r?\n/).filter(_ => _ !== ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1,2 @@
|
|||||||
<app-table [songs]="songs"></app-table>
|
<app-table></app-table>
|
||||||
|
<app-song></app-song>
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { SongsComponent } from './songs.component';
|
|
||||||
|
|
||||||
describe('SongsComponent', () => {
|
|
||||||
let component: SongsComponent;
|
|
||||||
let fixture: ComponentFixture<SongsComponent>;
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [ SongsComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(SongsComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,22 +1,13 @@
|
|||||||
import { Song } from './../../models/song.model';
|
import { Component } from '@angular/core';
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { SongsService } from 'src/app/data/songs.service';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-songs',
|
selector: 'app-songs',
|
||||||
templateUrl: './songs.component.html',
|
templateUrl: './songs.component.html',
|
||||||
styleUrls: ['./songs.component.less']
|
styleUrls: ['./songs.component.less']
|
||||||
})
|
})
|
||||||
export class SongsComponent implements OnInit {
|
export class SongsComponent {
|
||||||
public songs: Song[];
|
constructor(songService: SongsService) {
|
||||||
|
songService.loadSongList();
|
||||||
constructor(private route: ActivatedRoute) {}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.route.data.subscribe((data: { songs: Song[] }) => {
|
|
||||||
this.songs = data.songs;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
<div class="page-container mat-elevation-z8">
|
<div
|
||||||
|
class="page-container mat-elevation-z8"
|
||||||
|
[class.pinned]="selectedSongId !== 0"
|
||||||
|
>
|
||||||
<div class="table-container">
|
<div class="table-container">
|
||||||
<table
|
<table
|
||||||
*ngIf="songs"
|
|
||||||
mat-table
|
mat-table
|
||||||
[dataSource]="songs"
|
[dataSource]="songsService.songs | async"
|
||||||
class="mat-elevation-z8"
|
class="mat-elevation-z8"
|
||||||
>
|
>
|
||||||
<ng-container matColumnDef="Number">
|
<ng-container matColumnDef="Number">
|
||||||
@@ -18,25 +20,37 @@
|
|||||||
|
|
||||||
<ng-container matColumnDef="Key">
|
<ng-container matColumnDef="Key">
|
||||||
<th mat-header-cell *matHeaderCellDef></th>
|
<th mat-header-cell *matHeaderCellDef></th>
|
||||||
<td mat-cell *matCellDef="let element">{{ element.Key }}</td>
|
<td mat-cell *matCellDef="let element">
|
||||||
|
<mat-chip-list *ngIf="element.Key">
|
||||||
|
<mat-chip>{{ element.Key }}</mat-chip>
|
||||||
|
</mat-chip-list>
|
||||||
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="SongType">
|
<ng-container matColumnDef="SongType">
|
||||||
<th mat-header-cell *matHeaderCellDef></th>
|
<th mat-header-cell *matHeaderCellDef></th>
|
||||||
<td mat-cell *matCellDef="let element">{{ element.SongType }}</td>
|
<td mat-cell *matCellDef="let element">
|
||||||
|
<mat-chip-list *ngIf="element.SongType && element.SongType!=='None'">
|
||||||
|
<mat-chip [style.background-color]="renderSongType(element.SongType).color">{{ renderSongType(element.SongType).name }}</mat-chip>
|
||||||
|
</mat-chip-list>
|
||||||
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="Tempo">
|
<ng-container matColumnDef="Tempo">
|
||||||
<th mat-header-cell *matHeaderCellDef></th>
|
<th mat-header-cell *matHeaderCellDef></th>
|
||||||
<td mat-cell *matCellDef="let element">{{ element.Tempo }}</td>
|
<td mat-cell *matCellDef="let element">
|
||||||
|
<mat-chip-list *ngIf="element.Tempo">
|
||||||
|
<mat-chip>{{ element.Tempo }}</mat-chip>
|
||||||
|
</mat-chip-list>
|
||||||
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="columns; sticky: true"></tr>
|
<tr mat-header-row *matHeaderRowDef="columns; sticky: true"></tr>
|
||||||
<tr
|
<tr
|
||||||
|
[class.selected]="selectedSongId === row.ID"
|
||||||
mat-row
|
mat-row
|
||||||
*matRowDef="let row; columns: columns"
|
*matRowDef="let row; columns: columns"
|
||||||
[routerLink]="['/songs', row.ID]"
|
(click)="onClick(row.ID)"
|
||||||
routerLinkActive="router-link-active"
|
|
||||||
></tr>
|
></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
//background: #fffe;
|
||||||
|
|
||||||
}
|
}
|
||||||
.page-container {
|
|
||||||
height: 400px;
|
|
||||||
overflow: hidden;
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
.table-container {
|
.table-container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { TableComponent } from './table.component';
|
|
||||||
|
|
||||||
describe('TableComponent', () => {
|
|
||||||
let component: TableComponent;
|
|
||||||
let fixture: ComponentFixture<TableComponent>;
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [ TableComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(TableComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,26 +1,45 @@
|
|||||||
import { Component, OnInit, Input } from '@angular/core';
|
import { SongsService } from './../../../data/songs.service';
|
||||||
import { Song } from 'src/app/models/song.model';
|
import {
|
||||||
|
Component,
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
ChangeDetectorRef
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-table',
|
selector: 'app-table',
|
||||||
templateUrl: './table.component.html',
|
templateUrl: './table.component.html',
|
||||||
styleUrls: ['./table.component.less']
|
styleUrls: ['./table.component.less'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class TableComponent implements OnInit {
|
export class TableComponent {
|
||||||
@Input() public songs: Song[];
|
public selectedSongId = 0;
|
||||||
public columns = [
|
public columnsFull = ['Number', 'Name', 'Key', 'SongType', 'Tempo'];
|
||||||
'Number',
|
public columnsPinned = ['Number', 'Name'];
|
||||||
'Name',
|
public get columns(): string[] {
|
||||||
'Key',
|
return this.selectedSongId === 0 ? this.columnsFull : this.columnsPinned;
|
||||||
'SongType',
|
|
||||||
'Tempo',
|
|
||||||
];
|
|
||||||
|
|
||||||
constructor() { }
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
console.log(this.songs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public songsService: SongsService,
|
||||||
|
private change: ChangeDetectorRef
|
||||||
|
) {
|
||||||
|
songsService.selectedSong.subscribe(_ => {
|
||||||
|
this.selectedSongId = _ ? _.ID : 0;
|
||||||
|
this.change.markForCheck();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public renderSongType(songType: string) {
|
||||||
|
switch (songType) {
|
||||||
|
case 'Praise': return {name: 'Lobpreis', color: '#99FFB8'};
|
||||||
|
case 'Worship': return {name: 'Anbetung', color: '#C999FF'};
|
||||||
|
default: return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public onClick(id: number): void {
|
||||||
|
this.songsService.selectSong(id);
|
||||||
|
this.change.detectChanges();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { HttpClient } from '@angular/common/http';
|
|
||||||
import { Song } from '../models/song.model';
|
|
||||||
import { SongsService } from './songs.service';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class SongResolverService implements Resolve<Song> {
|
|
||||||
|
|
||||||
constructor(private songsService: SongsService) { }
|
|
||||||
|
|
||||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Song> {
|
|
||||||
const id = route.params.id;
|
|
||||||
const get$ = this.songsService.get<Song>(id);
|
|
||||||
return get$;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import { Song } from './../models/song.model';
|
|
||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { SongsService } from './songs.service';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class SongsResolverService implements Resolve<Song[]> {
|
|
||||||
|
|
||||||
constructor(private songsService: SongsService) { }
|
|
||||||
|
|
||||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Song[]> {
|
|
||||||
const get$ = this.songsService.list<Song>();
|
|
||||||
return get$;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,31 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { ODataService } from 'odata-v4-ng';
|
import { ODataService } from 'odata-v4-ng';
|
||||||
import { OdataService } from './odata.service';
|
import { OdataService } from './odata.service';
|
||||||
|
import { Song } from '../models/song.model';
|
||||||
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class SongsService extends OdataService {
|
export class SongsService extends OdataService {
|
||||||
|
public songs: BehaviorSubject<Song[]> = new BehaviorSubject<Song[]>([]);
|
||||||
|
public selectedSong: BehaviorSubject<Song> = new BehaviorSubject<Song>(null);
|
||||||
|
|
||||||
constructor(odataService: ODataService) {
|
constructor(odataService: ODataService) {
|
||||||
super(odataService, 'songs');
|
super(odataService, 'songs');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public loadSongList(): void {
|
||||||
|
this.list<Song>().subscribe(_ => this.songs.next(_));
|
||||||
|
}
|
||||||
|
|
||||||
|
public selectSong(id: number): void {
|
||||||
|
const filter = this.songs.value.filter(_ => _.ID === id);
|
||||||
|
const song = filter.length === 1 ? filter[0] : null;
|
||||||
|
this.selectedSong.next(song);
|
||||||
|
}
|
||||||
|
|
||||||
|
public resetSelectedSong() {
|
||||||
|
this.selectedSong.next(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,75 @@
|
|||||||
/* You can add global styles to this file, and also import other style files */
|
/* You can add global styles to this file, and also import other style files */
|
||||||
@import "~@angular/material/prebuilt-themes/indigo-pink.css";
|
@import "~@angular/material/prebuilt-themes/indigo-pink.css";
|
||||||
|
|
||||||
tbody {
|
|
||||||
|
body {
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
background-image: url(https://images.unsplash.com/photo-1476136236990-838240be4859?ixlib=rb-1.2.1&auto=format&fit=crop&w=2167&q=80);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-container {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
left: 20px;
|
||||||
|
bottom: 20px;
|
||||||
|
right: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: all 300ms ease-in-out;
|
||||||
|
.mat-table tbody {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
th.mat-header-cell:first-of-type {
|
||||||
|
border-top-left-radius: 8px;
|
||||||
|
transition: all 300ms ease-in-out;
|
||||||
|
}
|
||||||
|
th.mat-header-cell:last-of-type {
|
||||||
|
border-top-right-radius: 8px;
|
||||||
|
transition: all 300ms ease-in-out;
|
||||||
|
}
|
||||||
|
.mat-table thead {
|
||||||
|
border-top-right-radius: 8px;
|
||||||
|
border-top-left-radius: 8px;
|
||||||
|
transition: all 300ms ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.selected {
|
||||||
|
background-color: #0002;
|
||||||
|
}
|
||||||
tr:hover {
|
tr:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
background-color: #0001;
|
||||||
td {
|
td {
|
||||||
color: #ff9900;
|
color: #ff9900;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
td.mat-cell {
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.pinned {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 70vw;
|
||||||
|
border-radius: 0px;
|
||||||
|
th.mat-header-cell:first-of-type {
|
||||||
|
border-top-left-radius: 0px;
|
||||||
|
transition: all 300ms ease-in-out;
|
||||||
|
}
|
||||||
|
th.mat-header-cell:last-of-type {
|
||||||
|
border-top-right-radius: 0px;
|
||||||
|
transition: all 300ms ease-in-out;
|
||||||
|
}
|
||||||
|
.mat-table thead {
|
||||||
|
border-top-right-radius: 0px;
|
||||||
|
border-top-left-radius: 0px;
|
||||||
|
transition: all 300ms ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user