* initial commit

This commit is contained in:
Dávid Danyi 2018-05-10 16:39:05 +02:00
parent bc4fb64f59
commit 699753fc23
38 changed files with 877 additions and 31 deletions

View File

@ -23,6 +23,12 @@
"src/assets"
],
"styles": [
{
"input": "node_modules/@angular/material/prebuilt-themes/indigo-pink.css"
},
"node_modules/@fortawesome/fontawesome-free-webfonts/css/fa-solid.css",
"node_modules/@fortawesome/fontawesome-free-webfonts/css/fa-regular.css",
"node_modules/@fortawesome/fontawesome-free-webfonts/css/fontawesome.css",
"src/styles.css"
],
"scripts": []
@ -72,6 +78,9 @@
"tsConfig": "src/tsconfig.spec.json",
"karmaConfig": "src/karma.conf.js",
"styles": [
{
"input": "node_modules/@angular/material/prebuilt-themes/indigo-pink.css"
},
"styles.css"
],
"scripts": [],

21
package-lock.json generated
View File

@ -115,6 +115,14 @@
"tslib": "1.9.0"
}
},
"@angular/cdk": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-6.0.1.tgz",
"integrity": "sha512-f8WAY/PC4etTWhtPDuu5zRy+5+qUWSnW+6PidfYAHHdVGu+90H8qIKA27VOW/RWk+oZnl2SC2LVg4G7hggio+A==",
"requires": {
"tslib": "1.9.0"
}
},
"@angular/cli": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-6.0.0.tgz",
@ -352,6 +360,14 @@
"integrity": "sha512-ysNUM8uec9Kf5Te5HBT6b3G5CLlxOKAXtk+bY1sqbE9sMDZFWQhqR66QzfWdOPRyj9KKrwuKZd9ArMjAbOVNYw==",
"dev": true
},
"@angular/material": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@angular/material/-/material-6.0.1.tgz",
"integrity": "sha512-QbAFoE3wruv/XsAKJirGn0fSfmVIBMCrtGe55hZjOVhvRbrnXJ61VSr4zrO/LDPzT17yXhf3ZaB3Yp/4GmRk8w==",
"requires": {
"tslib": "1.9.0"
}
},
"@angular/platform-browser": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-6.0.0.tgz",
@ -376,6 +392,11 @@
"tslib": "1.9.0"
}
},
"@fortawesome/fontawesome-free-webfonts": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free-webfonts/-/fontawesome-free-webfonts-1.0.8.tgz",
"integrity": "sha512-pAeqqnpH2+uuUdSZJ0vmEtmtKhiatebzIrl4VDMPiB0lXkp2E+vFypp8MDTZhu7gF5XzdZRD0CCAwKz16u/x6Q=="
},
"@ngtools/webpack": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-6.0.0.tgz",

View File

@ -12,14 +12,17 @@
"private": true,
"dependencies": {
"@angular/animations": "^6.0.0",
"@angular/cdk": "^6.0.0",
"@angular/common": "^6.0.0",
"@angular/compiler": "^6.0.0",
"@angular/core": "^6.0.0",
"@angular/forms": "^6.0.0",
"@angular/http": "^6.0.0",
"@angular/material": "^6.0.1",
"@angular/platform-browser": "^6.0.0",
"@angular/platform-browser-dynamic": "^6.0.0",
"@angular/router": "^6.0.0",
"@fortawesome/fontawesome-free-webfonts": "^1.0.8",
"core-js": "^2.5.4",
"rxjs": "^6.0.0",
"zone.js": "^0.8.26"

View File

@ -1,7 +1,30 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [];
import { AwardeeListComponent } from "./awardee-list/awardee-list.component";
import { JudgeListComponent } from "./judge-list/judge-list.component";
import { AwardeeEditorComponent } from "./awardee-editor/awardee-editor.component";
import { JudgeEditorComponent } from "./judge-editor/judge-editor.component";
const routes: Routes = [
{
path: 'awardees',
component: AwardeeListComponent
// canActivate: [AuthGuardService, RoleGuardService],
}, {
path: 'awardee/new',
component: AwardeeEditorComponent
// canActivate: [AuthGuardService, RoleGuardService],
}, {
path: 'judges',
component: JudgeListComponent
// canActivate: [AuthGuardService, RoleGuardService],
}, {
path: 'judge/new',
component: JudgeEditorComponent
// canActivate: [AuthGuardService, RoleGuardService],
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],

View File

@ -1,21 +1,3 @@
<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
</div>
<h2>Here are some links to help you start: </h2>
<ul>
<li>
<h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2>
</li>
</ul>
<app-navigation>
<router-outlet></router-outlet>
</app-navigation>

View File

@ -5,6 +5,4 @@ import { Component } from '@angular/core';
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
}
export class AppComponent {}

View File

@ -1,16 +1,60 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { LayoutModule } from '@angular/cdk/layout';
import {
MatToolbarModule,
MatButtonModule,
MatSidenavModule,
MatIconModule,
MatListModule,
MatTableModule,
MatPaginatorModule,
MatSortModule,
MatFormFieldModule,
MatInputModule,
MatSelectModule,
MatOptionModule,
} from '@angular/material';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { NavigationComponent } from './navigation/navigation.component';
import { AwardeeListComponent } from './awardee-list/awardee-list.component';
import { JudgeListComponent } from './judge-list/judge-list.component';
import { JudgeListTableComponent } from './judge-list-table/judge-list-table.component';
import { AwardeeListTableComponent } from './awardee-list-table/awardee-list-table.component';
import { AwardeeEditorComponent } from './awardee-editor/awardee-editor.component';
import { JudgeEditorComponent } from './judge-editor/judge-editor.component';
@NgModule({
declarations: [
AppComponent
AppComponent,
NavigationComponent,
AwardeeListComponent,
JudgeListComponent,
JudgeListTableComponent,
AwardeeListTableComponent,
AwardeeEditorComponent,
JudgeEditorComponent
],
imports: [
BrowserModule,
AppRoutingModule
AppRoutingModule,
BrowserAnimationsModule,
LayoutModule,
MatToolbarModule,
MatButtonModule,
MatSidenavModule,
MatIconModule,
MatListModule,
MatTableModule,
MatPaginatorModule,
MatSortModule,
MatFormFieldModule,
MatInputModule,
MatSelectModule,
MatOptionModule,
],
providers: [],
bootstrap: [AppComponent]

View File

@ -0,0 +1,19 @@
:host {
display: block;
margin: 20px;
}
.awardee-form {
min-width: 150px;
max-width: 500px;
width: 100%;
}
.full-width {
width: 100%;
}
button + mat-divider {
margin-top: 10px;
margin-bottom: 10px;
}

View File

@ -0,0 +1,33 @@
<form class="awardee-form">
<mat-form-field class="full-width">
<input type="text" matInput placeholder="Display name">
</mat-form-field>
<button type="button" mat-raised-button>
<i class="far fa-image"></i>
Upload profile image
</button>
<mat-divider></mat-divider>
<mat-form-field class="full-width">
<mat-select placeholder="Year">
<mat-option *ngFor="let year of years" [value]="year">
{{ year }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="full-width">
<textarea matInput placeholder="Article text" rows="10"></textarea>
</mat-form-field>
<button type="button" mat-raised-button>
<i class="far fa-image"></i> Upload article image
</button>
<mat-divider></mat-divider>
<mat-form-field class="full-width">
<input type="text" matInput placeholder="Image label">
</mat-form-field>
<button type="submit" mat-raised-button color="accent">
<i class="fas fa-save"></i> Save
</button>
</form>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AwardeeEditorComponent } from './awardee-editor.component';
describe('AwardeeEditorComponent', () => {
let component: AwardeeEditorComponent;
let fixture: ComponentFixture<AwardeeEditorComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ AwardeeEditorComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AwardeeEditorComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,24 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-awardee-editor',
templateUrl: './awardee-editor.component.html',
styleUrls: ['./awardee-editor.component.css']
})
export class AwardeeEditorComponent implements OnInit {
public years: Array<number> = [
2018,
2017,
2016,
2015,
2014,
2013,
];
constructor() { }
ngOnInit() {
}
}

View File

@ -0,0 +1,108 @@
import { DataSource } from '@angular/cdk/collections';
import { MatPaginator, MatSort } from '@angular/material';
import { map } from 'rxjs/operators';
import { Observable, of as observableOf, merge } from 'rxjs';
// TODO: Replace this with your own data model type
export interface AwardeeListTableItem {
name: string;
id: number;
}
// TODO: replace this with real data from your application
const EXAMPLE_DATA: AwardeeListTableItem[] = [
{id: 1, name: 'Hydrogen'},
{id: 2, name: 'Helium'},
{id: 3, name: 'Lithium'},
{id: 4, name: 'Beryllium'},
{id: 5, name: 'Boron'},
{id: 6, name: 'Carbon'},
{id: 7, name: 'Nitrogen'},
{id: 8, name: 'Oxygen'},
{id: 9, name: 'Fluorine'},
{id: 10, name: 'Neon'},
{id: 11, name: 'Sodium'},
{id: 12, name: 'Magnesium'},
{id: 13, name: 'Aluminum'},
{id: 14, name: 'Silicon'},
{id: 15, name: 'Phosphorus'},
{id: 16, name: 'Sulfur'},
{id: 17, name: 'Chlorine'},
{id: 18, name: 'Argon'},
{id: 19, name: 'Potassium'},
{id: 20, name: 'Calcium'},
];
/**
* Data source for the AwardeeListTable view. This class should
* encapsulate all logic for fetching and manipulating the displayed data
* (including sorting, pagination, and filtering).
*/
export class AwardeeListTableDataSource extends DataSource<AwardeeListTableItem> {
data: AwardeeListTableItem[] = EXAMPLE_DATA;
constructor(private paginator: MatPaginator, private sort: MatSort) {
super();
}
/**
* Connect this data source to the table. The table will only update when
* the returned stream emits new items.
* @returns A stream of the items to be rendered.
*/
connect(): Observable<AwardeeListTableItem[]> {
// Combine everything that affects the rendered data into one update
// stream for the data-table to consume.
const dataMutations = [
observableOf(this.data),
this.paginator.page,
this.sort.sortChange
];
// Set the paginators length
this.paginator.length = this.data.length;
return merge(...dataMutations).pipe(map(() => {
return this.getPagedData(this.getSortedData([...this.data]));
}));
}
/**
* Called when the table is being destroyed. Use this function, to clean up
* any open connections or free any held resources that were set up during connect.
*/
disconnect() {}
/**
* Paginate the data (client-side). If you're using server-side pagination,
* this would be replaced by requesting the appropriate data from the server.
*/
private getPagedData(data: AwardeeListTableItem[]) {
const startIndex = this.paginator.pageIndex * this.paginator.pageSize;
return data.splice(startIndex, this.paginator.pageSize);
}
/**
* Sort the data (client-side). If you're using server-side sorting,
* this would be replaced by requesting the appropriate data from the server.
*/
private getSortedData(data: AwardeeListTableItem[]) {
if (!this.sort.active || this.sort.direction === '') {
return data;
}
return data.sort((a, b) => {
const isAsc = this.sort.direction === 'asc';
switch (this.sort.active) {
case 'name': return compare(a.name, b.name, isAsc);
case 'id': return compare(+a.id, +b.id, isAsc);
default: return 0;
}
});
}
}
/** Simple sort comparator for example ID/Name columns (for client-side sorting). */
function compare(a, b, isAsc) {
return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
}

View File

@ -0,0 +1,4 @@
:host {
display: block;
margin-top: 20px;
}

View File

@ -0,0 +1,26 @@
<div class="mat-elevation-z8">
<mat-table #table [dataSource]="dataSource" matSort aria-label="Elements">
<!-- Id Column -->
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef mat-sort-header>Id</mat-header-cell>
<mat-cell *matCellDef="let row">{{row.id}}</mat-cell>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
<mat-cell *matCellDef="let row">{{row.name}}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
<mat-paginator #paginator
[length]="dataSource.data.length"
[pageIndex]="0"
[pageSize]="50"
[pageSizeOptions]="[25, 50, 100, 250]">
</mat-paginator>
</div>

View File

@ -0,0 +1,24 @@
import { fakeAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { AwardeeListTableComponent } from './awardee-list-table.component';
describe('AwardeeListTableComponent', () => {
let component: AwardeeListTableComponent;
let fixture: ComponentFixture<AwardeeListTableComponent>;
beforeEach(fakeAsync(() => {
TestBed.configureTestingModule({
declarations: [ AwardeeListTableComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(AwardeeListTableComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should compile', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,21 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { MatPaginator, MatSort } from '@angular/material';
import { AwardeeListTableDataSource } from './awardee-list-table-datasource';
@Component({
selector: 'awardee-list-table',
templateUrl: './awardee-list-table.component.html',
styleUrls: ['./awardee-list-table.component.css']
})
export class AwardeeListTableComponent implements OnInit {
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
dataSource: AwardeeListTableDataSource;
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns = ['id', 'name'];
ngOnInit() {
this.dataSource = new AwardeeListTableDataSource(this.paginator, this.sort);
}
}

View File

@ -0,0 +1,4 @@
:host {
display: block;
margin: 20px;
}

View File

@ -0,0 +1,5 @@
<a class="mat-raised-button" [routerLink]="['/awardee/new']">
<mat-icon fontSet="fas" fontIcon="fa-user-plus"></mat-icon>
New awardee
</a>
<awardee-list-table></awardee-list-table>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AwardeeListComponent } from './awardee-list.component';
describe('AwardeeListComponent', () => {
let component: AwardeeListComponent;
let fixture: ComponentFixture<AwardeeListComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ AwardeeListComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AwardeeListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-awardee-list',
templateUrl: './awardee-list.component.html',
styleUrls: ['./awardee-list.component.css']
})
export class AwardeeListComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}

View File

@ -0,0 +1,29 @@
:host {
display: block;
margin: 20px;
}
.judge-form {
min-width: 150px;
max-width: 500px;
width: 100%;
}
.full-width {
width: 100%;
}
.half-width {
width: calc(50% - 10px);
margin-right: 10px;
}
.half-width:last-of-type {
width: calc(50%);
margin-right: 0;
}
button + mat-divider {
margin-top: 10px;
margin-bottom: 10px;
}

View File

@ -0,0 +1,38 @@
<form class="judge-form">
<mat-form-field class="full-width">
<input type="text" matInput placeholder="Display name">
</mat-form-field>
<button type="button" mat-raised-button>
<i class="far fa-image"></i>
Upload profile image
</button>
<mat-divider></mat-divider>
<mat-form-field class="half-width">
<input type="number" matInput placeholder="Year">
</mat-form-field>
<mat-form-field class="half-width">
<input type="text" matInput placeholder="Title">
</mat-form-field>
<mat-table [dataSource]="judge.yearlyData">
<ng-container matColumnDef="year">
<mat-header-cell *matHeaderCellDef>Year</mat-header-cell>
<mat-cell *matCellDef="let row">{{row.year}}</mat-cell>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="title">
<mat-header-cell *matHeaderCellDef>Title</mat-header-cell>
<mat-cell *matCellDef="let row">{{row.title}}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
<button type="submit" mat-raised-button color="accent">
<i class="fas fa-save"></i> Save
</button>
</form>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { JudgeEditorComponent } from './judge-editor.component';
describe('JudgeEditorComponent', () => {
let component: JudgeEditorComponent;
let fixture: ComponentFixture<JudgeEditorComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ JudgeEditorComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(JudgeEditorComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,25 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-judge-editor',
templateUrl: './judge-editor.component.html',
styleUrls: ['./judge-editor.component.css']
})
export class JudgeEditorComponent implements OnInit {
public displayedColumns = ['year', 'title'];
public judge = {
yearlyData: [
{
year: 2013,
title: 'Something something dark side',
}
]
};
constructor() {}
ngOnInit() {
}
}

View File

@ -0,0 +1,108 @@
import { DataSource } from '@angular/cdk/collections';
import { MatPaginator, MatSort } from '@angular/material';
import { map } from 'rxjs/operators';
import { Observable, of as observableOf, merge } from 'rxjs';
// TODO: Replace this with your own data model type
export interface JudgeListTableItem {
name: string;
id: number;
}
// TODO: replace this with real data from your application
const EXAMPLE_DATA: JudgeListTableItem[] = [
{id: 1, name: 'Hydrogen'},
{id: 2, name: 'Helium'},
{id: 3, name: 'Lithium'},
{id: 4, name: 'Beryllium'},
{id: 5, name: 'Boron'},
{id: 6, name: 'Carbon'},
{id: 7, name: 'Nitrogen'},
{id: 8, name: 'Oxygen'},
{id: 9, name: 'Fluorine'},
{id: 10, name: 'Neon'},
{id: 11, name: 'Sodium'},
{id: 12, name: 'Magnesium'},
{id: 13, name: 'Aluminum'},
{id: 14, name: 'Silicon'},
{id: 15, name: 'Phosphorus'},
{id: 16, name: 'Sulfur'},
{id: 17, name: 'Chlorine'},
{id: 18, name: 'Argon'},
{id: 19, name: 'Potassium'},
{id: 20, name: 'Calcium'},
];
/**
* Data source for the JudgeListTable view. This class should
* encapsulate all logic for fetching and manipulating the displayed data
* (including sorting, pagination, and filtering).
*/
export class JudgeListTableDataSource extends DataSource<JudgeListTableItem> {
data: JudgeListTableItem[] = EXAMPLE_DATA;
constructor(private paginator: MatPaginator, private sort: MatSort) {
super();
}
/**
* Connect this data source to the table. The table will only update when
* the returned stream emits new items.
* @returns A stream of the items to be rendered.
*/
connect(): Observable<JudgeListTableItem[]> {
// Combine everything that affects the rendered data into one update
// stream for the data-table to consume.
const dataMutations = [
observableOf(this.data),
this.paginator.page,
this.sort.sortChange
];
// Set the paginators length
this.paginator.length = this.data.length;
return merge(...dataMutations).pipe(map(() => {
return this.getPagedData(this.getSortedData([...this.data]));
}));
}
/**
* Called when the table is being destroyed. Use this function, to clean up
* any open connections or free any held resources that were set up during connect.
*/
disconnect() {}
/**
* Paginate the data (client-side). If you're using server-side pagination,
* this would be replaced by requesting the appropriate data from the server.
*/
private getPagedData(data: JudgeListTableItem[]) {
const startIndex = this.paginator.pageIndex * this.paginator.pageSize;
return data.splice(startIndex, this.paginator.pageSize);
}
/**
* Sort the data (client-side). If you're using server-side sorting,
* this would be replaced by requesting the appropriate data from the server.
*/
private getSortedData(data: JudgeListTableItem[]) {
if (!this.sort.active || this.sort.direction === '') {
return data;
}
return data.sort((a, b) => {
const isAsc = this.sort.direction === 'asc';
switch (this.sort.active) {
case 'name': return compare(a.name, b.name, isAsc);
case 'id': return compare(+a.id, +b.id, isAsc);
default: return 0;
}
});
}
}
/** Simple sort comparator for example ID/Name columns (for client-side sorting). */
function compare(a, b, isAsc) {
return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
}

View File

@ -0,0 +1,4 @@
:host {
display: block;
margin-top: 20px;
}

View File

@ -0,0 +1,26 @@
<div class="mat-elevation-z8">
<mat-table #table [dataSource]="dataSource" matSort aria-label="Elements">
<!-- Id Column -->
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef mat-sort-header>Id</mat-header-cell>
<mat-cell *matCellDef="let row">{{row.id}}</mat-cell>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
<mat-cell *matCellDef="let row">{{row.name}}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
<mat-paginator #paginator
[length]="dataSource.data.length"
[pageIndex]="0"
[pageSize]="50"
[pageSizeOptions]="[25, 50, 100, 250]">
</mat-paginator>
</div>

View File

@ -0,0 +1,24 @@
import { fakeAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { JudgeListTableComponent } from './judge-list-table.component';
describe('JudgeListTableComponent', () => {
let component: JudgeListTableComponent;
let fixture: ComponentFixture<JudgeListTableComponent>;
beforeEach(fakeAsync(() => {
TestBed.configureTestingModule({
declarations: [ JudgeListTableComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(JudgeListTableComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should compile', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,21 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { MatPaginator, MatSort } from '@angular/material';
import { JudgeListTableDataSource } from './judge-list-table-datasource';
@Component({
selector: 'judge-list-table',
templateUrl: './judge-list-table.component.html',
styleUrls: ['./judge-list-table.component.css']
})
export class JudgeListTableComponent implements OnInit {
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
dataSource: JudgeListTableDataSource;
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns = ['id', 'name'];
ngOnInit() {
this.dataSource = new JudgeListTableDataSource(this.paginator, this.sort);
}
}

View File

@ -0,0 +1,4 @@
:host {
display: block;
margin: 20px;
}

View File

@ -0,0 +1,5 @@
<a class="mat-raised-button" [routerLink]="['/judge/new']">
<mat-icon fontSet="fas" fontIcon="fa-user-plus"></mat-icon>
New judge
</a>
<judge-list-table></judge-list-table>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { JudgeListComponent } from './judge-list.component';
describe('JudgeListComponent', () => {
let component: JudgeListComponent;
let fixture: ComponentFixture<JudgeListComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ JudgeListComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(JudgeListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-judge-list',
templateUrl: './judge-list.component.html',
styleUrls: ['./judge-list.component.css']
})
export class JudgeListComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}

View File

@ -0,0 +1,8 @@
.sidenav-container {
height: 100%;
}
.sidenav {
width: 200px;
box-shadow: 3px 0 6px rgba(0,0,0,.24);
}

View File

@ -0,0 +1,30 @@
<mat-sidenav-container class="sidenav-container">
<mat-sidenav
#drawer
class="sidenav"
fixedInViewport="true"
[attr.role]="isHandset ? 'dialog' : 'navigation'"
[mode]="(isHandset | async)!.matches ? 'over' : 'side'"
[opened]="!(isHandset | async)!.matches">
<mat-toolbar color="primary">Menu</mat-toolbar>
<mat-nav-list>
<a mat-list-item [routerLink]="['awardees']">Awardees</a>
<a mat-list-item [routerLink]="['judges']">Judges</a>
<a mat-list-item [routerLink]="['awardees']">Years</a>
</mat-nav-list>
</mat-sidenav>
<mat-sidenav-content>
<mat-toolbar color="primary">
<button
type="button"
aria-label="Toggle sidenav"
mat-icon-button
(click)="drawer.toggle()"
*ngIf="(isHandset | async)!.matches">
<mat-icon aria-label="Side nav toggle icon">menu</mat-icon>
</button>
<span>{{title}}</span>
</mat-toolbar>
<ng-content></ng-content>
</mat-sidenav-content>
</mat-sidenav-container>

View File

@ -0,0 +1,24 @@
import { fakeAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { NavigationComponent } from './navigation.component';
describe('NavigationComponent', () => {
let component: NavigationComponent;
let fixture: ComponentFixture<NavigationComponent>;
beforeEach(fakeAsync(() => {
TestBed.configureTestingModule({
declarations: [ NavigationComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(NavigationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should compile', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,20 @@
import { Component } from '@angular/core';
import { BreakpointObserver, Breakpoints, BreakpointState } from '@angular/cdk/layout';
import { Observable } from 'rxjs';
import { Title } from "@angular/platform-browser";
@Component({
selector: 'app-navigation',
templateUrl: './navigation.component.html',
styleUrls: ['./navigation.component.css']
})
export class NavigationComponent {
isHandset: Observable<BreakpointState> = this.breakpointObserver.observe(Breakpoints.Handset);
constructor(
private breakpointObserver: BreakpointObserver,
private titleService: Title
) {}
get title(): string {
return this.titleService.getTitle();
}
}

View File

@ -1,8 +1,10 @@
<!doctype html>
<html lang="en">
<head>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet">
<meta charset="utf-8">
<title>SwedishchamberGranprizeAdmin</title>
<title>Gran Prize :: Admin</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">