* initial commit
This commit is contained in:
parent
bc4fb64f59
commit
699753fc23
@ -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
21
package-lock.json
generated
@ -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",
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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)],
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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 {}
|
||||
|
||||
@ -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]
|
||||
|
||||
19
src/app/awardee-editor/awardee-editor.component.css
Normal file
19
src/app/awardee-editor/awardee-editor.component.css
Normal 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;
|
||||
}
|
||||
33
src/app/awardee-editor/awardee-editor.component.html
Normal file
33
src/app/awardee-editor/awardee-editor.component.html
Normal 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>
|
||||
25
src/app/awardee-editor/awardee-editor.component.spec.ts
Normal file
25
src/app/awardee-editor/awardee-editor.component.spec.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
24
src/app/awardee-editor/awardee-editor.component.ts
Normal file
24
src/app/awardee-editor/awardee-editor.component.ts
Normal 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() {
|
||||
}
|
||||
|
||||
}
|
||||
108
src/app/awardee-list-table/awardee-list-table-datasource.ts
Normal file
108
src/app/awardee-list-table/awardee-list-table-datasource.ts
Normal 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);
|
||||
}
|
||||
@ -0,0 +1,4 @@
|
||||
:host {
|
||||
display: block;
|
||||
margin-top: 20px;
|
||||
}
|
||||
26
src/app/awardee-list-table/awardee-list-table.component.html
Normal file
26
src/app/awardee-list-table/awardee-list-table.component.html
Normal 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>
|
||||
@ -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();
|
||||
});
|
||||
});
|
||||
21
src/app/awardee-list-table/awardee-list-table.component.ts
Normal file
21
src/app/awardee-list-table/awardee-list-table.component.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
4
src/app/awardee-list/awardee-list.component.css
Normal file
4
src/app/awardee-list/awardee-list.component.css
Normal file
@ -0,0 +1,4 @@
|
||||
:host {
|
||||
display: block;
|
||||
margin: 20px;
|
||||
}
|
||||
5
src/app/awardee-list/awardee-list.component.html
Normal file
5
src/app/awardee-list/awardee-list.component.html
Normal 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>
|
||||
25
src/app/awardee-list/awardee-list.component.spec.ts
Normal file
25
src/app/awardee-list/awardee-list.component.spec.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
15
src/app/awardee-list/awardee-list.component.ts
Normal file
15
src/app/awardee-list/awardee-list.component.ts
Normal 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() {
|
||||
}
|
||||
|
||||
}
|
||||
29
src/app/judge-editor/judge-editor.component.css
Normal file
29
src/app/judge-editor/judge-editor.component.css
Normal 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;
|
||||
}
|
||||
38
src/app/judge-editor/judge-editor.component.html
Normal file
38
src/app/judge-editor/judge-editor.component.html
Normal 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>
|
||||
25
src/app/judge-editor/judge-editor.component.spec.ts
Normal file
25
src/app/judge-editor/judge-editor.component.spec.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
25
src/app/judge-editor/judge-editor.component.ts
Normal file
25
src/app/judge-editor/judge-editor.component.ts
Normal 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() {
|
||||
}
|
||||
|
||||
}
|
||||
108
src/app/judge-list-table/judge-list-table-datasource.ts
Normal file
108
src/app/judge-list-table/judge-list-table-datasource.ts
Normal 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);
|
||||
}
|
||||
4
src/app/judge-list-table/judge-list-table.component.css
Normal file
4
src/app/judge-list-table/judge-list-table.component.css
Normal file
@ -0,0 +1,4 @@
|
||||
:host {
|
||||
display: block;
|
||||
margin-top: 20px;
|
||||
}
|
||||
26
src/app/judge-list-table/judge-list-table.component.html
Normal file
26
src/app/judge-list-table/judge-list-table.component.html
Normal 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>
|
||||
24
src/app/judge-list-table/judge-list-table.component.spec.ts
Normal file
24
src/app/judge-list-table/judge-list-table.component.spec.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
21
src/app/judge-list-table/judge-list-table.component.ts
Normal file
21
src/app/judge-list-table/judge-list-table.component.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
4
src/app/judge-list/judge-list.component.css
Normal file
4
src/app/judge-list/judge-list.component.css
Normal file
@ -0,0 +1,4 @@
|
||||
:host {
|
||||
display: block;
|
||||
margin: 20px;
|
||||
}
|
||||
5
src/app/judge-list/judge-list.component.html
Normal file
5
src/app/judge-list/judge-list.component.html
Normal 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>
|
||||
25
src/app/judge-list/judge-list.component.spec.ts
Normal file
25
src/app/judge-list/judge-list.component.spec.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
15
src/app/judge-list/judge-list.component.ts
Normal file
15
src/app/judge-list/judge-list.component.ts
Normal 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() {
|
||||
}
|
||||
|
||||
}
|
||||
8
src/app/navigation/navigation.component.css
Normal file
8
src/app/navigation/navigation.component.css
Normal file
@ -0,0 +1,8 @@
|
||||
.sidenav-container {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.sidenav {
|
||||
width: 200px;
|
||||
box-shadow: 3px 0 6px rgba(0,0,0,.24);
|
||||
}
|
||||
30
src/app/navigation/navigation.component.html
Normal file
30
src/app/navigation/navigation.component.html
Normal 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>
|
||||
24
src/app/navigation/navigation.component.spec.ts
Normal file
24
src/app/navigation/navigation.component.spec.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
20
src/app/navigation/navigation.component.ts
Normal file
20
src/app/navigation/navigation.component.ts
Normal 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();
|
||||
}
|
||||
}
|
||||
@ -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">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user