├── src ├── assets │ ├── .gitkeep │ ├── logo.png │ ├── logos.png │ └── logo.svg ├── styles.scss ├── sass │ ├── partials │ │ ├── index.scss │ │ ├── _login.scss │ │ └── _home.scss │ ├── base │ │ ├── index.scss │ │ ├── _variables.scss │ │ ├── _reset.scss │ │ ├── _typography.scss │ │ └── _layout.scss │ ├── components │ │ ├── index.scss │ │ ├── _tabs.scss │ │ ├── _buttons.scss │ │ ├── _lists.scss │ │ ├── _table.scss │ │ ├── _nav.scss │ │ └── _alerts.scss │ ├── themes │ │ ├── index.scss │ │ ├── _theme.scss │ │ ├── _light-theme.scss │ │ ├── _dark-theme.scss │ │ ├── _mixed-theme.scss │ │ ├── _black-theme.scss │ │ └── _snow-white-theme.scss │ ├── main.scss │ └── utils │ │ ├── _spinners.scss │ │ ├── _margins.scss │ │ └── _flex.scss ├── app │ ├── components │ │ ├── users │ │ │ ├── models │ │ │ │ ├── index.ts │ │ │ │ └── user.model.ts │ │ │ ├── services │ │ │ │ ├── index.ts │ │ │ │ └── user.service.ts │ │ │ ├── list │ │ │ │ ├── user-list.component.spec.ts │ │ │ │ ├── user-list.component.ts │ │ │ │ └── user-list.component.html │ │ │ ├── details │ │ │ │ ├── user-details.component.spec.ts │ │ │ │ ├── user-details.component.ts │ │ │ │ └── user-details.component.html │ │ │ └── shared │ │ │ │ └── create-edit-user │ │ │ │ ├── create-edit-user.component.spec.ts │ │ │ │ ├── create-edit-user.component.html │ │ │ │ └── create-edit-user.component.ts │ │ ├── login │ │ │ ├── login.component.ts │ │ │ ├── login.component.spec.ts │ │ │ └── login.component.html │ │ ├── shared │ │ │ ├── navbar │ │ │ │ ├── navbar.component.ts │ │ │ │ └── navbar.component.html │ │ │ └── toolbar │ │ │ │ ├── toolbar.component.html │ │ │ │ └── toolbar.component.ts │ │ ├── layout │ │ │ ├── typography │ │ │ │ ├── typography.component.ts │ │ │ │ ├── typography.component.spec.ts │ │ │ │ └── typography.component.html │ │ │ ├── alerts-layout │ │ │ │ ├── alerts-layout.component.ts │ │ │ │ ├── alerts-layout.component.spec.ts │ │ │ │ └── alerts-layout.component.html │ │ │ ├── base │ │ │ │ ├── layout.component.ts │ │ │ │ ├── layout.component.spec.ts │ │ │ │ └── layout.component.html │ │ │ └── buttons-layout │ │ │ │ ├── buttons-layout.component.ts │ │ │ │ ├── buttons-layout.component.spec.ts │ │ │ │ └── buttons-layout.component.html │ │ ├── profile │ │ │ ├── profile.component.ts │ │ │ ├── profile.component.html │ │ │ └── profile.component.spec.ts │ │ ├── dialogs │ │ │ └── confirm-dialog │ │ │ │ ├── confirm-dialog.component.html │ │ │ │ ├── confirm-dialog.component.ts │ │ │ │ └── confirm-dialog.component.spec.ts │ │ ├── app │ │ │ ├── app.component.ts │ │ │ └── app.component.spec.ts │ │ ├── home │ │ │ ├── home.component.spec.ts │ │ │ ├── home.component.ts │ │ │ └── home.component.html │ │ └── settings │ │ │ ├── settings.component.spec.ts │ │ │ ├── settings.component.html │ │ │ └── settings.component.ts │ ├── services │ │ ├── index.ts │ │ ├── http.service.ts │ │ └── theme.service.ts │ ├── layouts │ │ ├── login-layout │ │ │ ├── login-layout.component.ts │ │ │ └── login-layout.component.spec.ts │ │ └── main-layout │ │ │ ├── main-layout.component.html │ │ │ ├── main-layout.component.spec.ts │ │ │ └── main-layout.component.ts │ ├── directives │ │ └── ng-init.directive.ts │ └── app.module.ts ├── favicon.ico ├── typings.d.ts ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── tsconfig.app.json ├── tsconfig.spec.json ├── main.ts ├── test.ts ├── index.html └── polyfills.ts ├── compilerconfig.json ├── e2e ├── app.po.ts ├── tsconfig.e2e.json └── app.e2e-spec.ts ├── .editorconfig ├── tsconfig.json ├── .gitignore ├── protractor.conf.js ├── karma.conf.js ├── compilerconfig.json.defaults ├── README.md ├── .angular-cli.json ├── package.json └── tslint.json /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | @import 'sass/main'; 2 | -------------------------------------------------------------------------------- /src/sass/partials/index.scss: -------------------------------------------------------------------------------- 1 | @import '_home'; 2 | @import '_login'; 3 | -------------------------------------------------------------------------------- /src/app/components/users/models/index.ts: -------------------------------------------------------------------------------- 1 | export { User } from './user.model'; 2 | -------------------------------------------------------------------------------- /src/app/components/users/services/index.ts: -------------------------------------------------------------------------------- 1 | export { UserService } from './user.service'; 2 | -------------------------------------------------------------------------------- /src/sass/base/index.scss: -------------------------------------------------------------------------------- 1 | @import '_reset'; 2 | @import '_layout'; 3 | @import '_typography'; 4 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aronium/angular-material-boilerplate/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aronium/angular-material-boilerplate/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/logos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aronium/angular-material-boilerplate/HEAD/src/assets/logos.png -------------------------------------------------------------------------------- /src/app/services/index.ts: -------------------------------------------------------------------------------- 1 | export { HttpService } from './http.service'; 2 | export { ThemeService } from './theme.service'; 3 | -------------------------------------------------------------------------------- /compilerconfig.json: -------------------------------------------------------------------------------- 1 | [ 2 | //{ 3 | // "outputFile": "src/sass/main.css", 4 | // "inputFile": "src/sass/main.scss" 5 | //} 6 | ] 7 | -------------------------------------------------------------------------------- /src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | baseUrl: "https://jsonplaceholder.typicode.com" 4 | }; 5 | -------------------------------------------------------------------------------- /src/sass/base/_variables.scss: -------------------------------------------------------------------------------- 1 | $heading-font-family: 'Roboto Condensed',sans-serif; 2 | 3 | $sidenav-width: 200px; 4 | $light-border-color: rgba(0,0,0,0.12); 5 | -------------------------------------------------------------------------------- /src/sass/components/index.scss: -------------------------------------------------------------------------------- 1 | @import "_alerts"; 2 | @import "_buttons"; 3 | @import "_lists"; 4 | @import "_table"; 5 | @import "_tabs"; 6 | @import "_nav"; 7 | -------------------------------------------------------------------------------- /src/app/components/users/models/user.model.ts: -------------------------------------------------------------------------------- 1 | export class User { 2 | name: string = ""; 3 | email: string = ""; 4 | username: string = ""; 5 | phone: string = ""; 6 | } 7 | -------------------------------------------------------------------------------- /src/sass/themes/index.scss: -------------------------------------------------------------------------------- 1 | @import '_theme'; 2 | @import '_light-theme'; 3 | @import '_mixed-theme'; 4 | @import '_snow-white-theme'; 5 | @import '_dark-theme'; 6 | @import '_black-theme'; 7 | -------------------------------------------------------------------------------- /src/app/components/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-login', 5 | templateUrl: './login.component.html' 6 | }) 7 | export class LoginComponent{ } 8 | -------------------------------------------------------------------------------- /src/app/components/shared/navbar/navbar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-navbar', 5 | templateUrl: './navbar.component.html' 6 | }) 7 | export class NavBarComponent { } 8 | -------------------------------------------------------------------------------- /src/app/components/layout/typography/typography.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-typography', 5 | templateUrl: './typography.component.html' 6 | }) 7 | export class TypographyComponent{ } 8 | -------------------------------------------------------------------------------- /e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/app/components/layout/alerts-layout/alerts-layout.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-alerts-layout', 5 | templateUrl: './alerts-layout.component.html' 6 | }) 7 | export class AlertsLayoutComponent { } 8 | -------------------------------------------------------------------------------- /src/app/components/layout/base/layout.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-layout', 5 | templateUrl: './layout.component.html' 6 | }) 7 | export class LayoutComponent { 8 | constructor() { } 9 | } 10 | -------------------------------------------------------------------------------- /src/app/layouts/login-layout/login-layout.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-login-layout', 5 | template: '', 6 | styles: [] 7 | }) 8 | export class LoginLayoutComponent { } 9 | -------------------------------------------------------------------------------- /src/app/components/layout/buttons-layout/buttons-layout.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-buttons-layout', 5 | templateUrl: './buttons-layout.component.html' 6 | }) 7 | export class ButtonsLayoutComponent { } 8 | -------------------------------------------------------------------------------- /src/sass/base/_reset.scss: -------------------------------------------------------------------------------- 1 | html, body{ 2 | margin: 0; 3 | padding: 0; 4 | } 5 | body { 6 | font-family: Roboto, "Helvetica Neue", sans-serif; 7 | font-size: 14px; 8 | -webkit-font-smoothing: antialiased; 9 | } 10 | 11 | main { 12 | padding: 16px; 13 | } 14 | -------------------------------------------------------------------------------- /src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "./", 6 | "module": "es2015", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /src/sass/main.scss: -------------------------------------------------------------------------------- 1 | // Utils 2 | @import 'utils/_margins'; 3 | @import 'utils/_spinners'; 4 | 5 | // Themes 6 | @import 'themes/index'; 7 | 8 | // Base styles 9 | @import 'base/index'; 10 | 11 | // Components 12 | @import 'components/index'; 13 | 14 | // Partials / pages 15 | @import 'partials/index'; 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "jasminewd2", 11 | "node" 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/app/components/profile/profile.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-profile', 5 | templateUrl: './profile.component.html' 6 | }) 7 | export class ProfileComponent implements OnInit { 8 | 9 | constructor() { } 10 | 11 | ngOnInit() { 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/app/components/dialogs/confirm-dialog/confirm-dialog.component.html: -------------------------------------------------------------------------------- 1 |

{{ data.title }}

2 |
3 | {{ data.message }} 4 |
5 |
6 | 7 | 8 |
-------------------------------------------------------------------------------- /e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('aronium-inside App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('Welcome to app!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/app/directives/ng-init.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, Input } from '@angular/core'; 2 | 3 | @Directive({ 4 | selector: '[ngInit]', 5 | exportAs: 'ngInit' 6 | }) 7 | export class NgInitDirective { 8 | 9 | @Input() value: any = {}; 10 | 11 | @Input() ngInit; 12 | ngOnInit() { 13 | if(this.ngInit) { 14 | this.ngInit(); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/sass/components/_tabs.scss: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // Tabs 3 | ////////////////////////////////////////////////////////////////////////////// 4 | 5 | .tabs-centered{ 6 | .mat-tab-labels{ 7 | justify-content: center; 8 | } 9 | 10 | &.no-border{ 11 | .mat-tab-header{ 12 | margin: 0 auto; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /src/sass/components/_buttons.scss: -------------------------------------------------------------------------------- 1 | .theme-selector-button{ 2 | .mat-button-toggle-label-content{ 3 | line-height: 32px; 4 | padding: 0 8px; 5 | .theme-indicator{ 6 | color: currentColor; 7 | border: 2px solid currentColor; 8 | border-radius: 50%; 9 | 10 | width: 16px!important; 11 | height: 16px!important; 12 | font-size: 16px!important; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/app/components/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Inject } from '@angular/core'; 2 | import { ThemeService } from '../../services'; 3 | 4 | @Component({ 5 | selector: 'app-root', 6 | template: '', 7 | providers: [ ThemeService ] 8 | }) 9 | export class AppComponent { 10 | 11 | constructor(private themeService: ThemeService){ 12 | themeService.loadSavedTheme(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/app/components/users/services/user.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpService } from '../../../services'; 3 | 4 | @Injectable() 5 | export class UserService { 6 | 7 | constructor(private http: HttpService) { 8 | } 9 | 10 | getUsers() { 11 | return this.http.get('/users'); 12 | } 13 | 14 | getUser(id: any){ 15 | return this.http.get(`/users/${id}`); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | import 'hammerjs'; 8 | 9 | if (environment.production) { 10 | enableProdMode(); 11 | } 12 | 13 | platformBrowserDynamic().bootstrapModule(AppModule) 14 | .catch(err => console.log(err)); 15 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "target": "es5", 11 | "typeRoots": [ 12 | "node_modules/@types" 13 | ], 14 | "lib": [ 15 | "es2017", 16 | "dom" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/app/components/dialogs/confirm-dialog/confirm-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject} from '@angular/core'; 2 | import {MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material' 3 | 4 | @Component({ 5 | selector: 'app-confirm-dialog', 6 | templateUrl: './confirm-dialog.component.html' 7 | }) 8 | export class ConfirmDialogComponent { 9 | constructor(public dialogRef: MatDialogRef, 10 | @Inject(MAT_DIALOG_DATA) public data: any) { } 11 | } 12 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false, 8 | baseUrl: "https://jsonplaceholder.typicode.com" 9 | }; 10 | -------------------------------------------------------------------------------- /src/app/layouts/main-layout/main-layout.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 |
13 | 14 |
15 | -------------------------------------------------------------------------------- /src/sass/utils/_spinners.scss: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes spin-reverse { 2 | 0% { 3 | -webkit-transform: rotate(0deg); 4 | transform: rotate(0deg); 5 | } 6 | 100% { 7 | -webkit-transform: rotate(-360deg); 8 | transform: rotate(-360deg); 9 | } 10 | } 11 | 12 | @keyframes spin-reverse { 13 | 0% { 14 | -webkit-transform: rotate(0deg); 15 | transform: rotate(0deg); 16 | } 17 | 100% { 18 | -webkit-transform: rotate(-360deg); 19 | transform: rotate(-360deg); 20 | } 21 | } 22 | 23 | .spin-reverse{ 24 | -webkit-animation: spin-reverse 2s infinite linear; 25 | animation: spin-reverse 2s infinite linear; 26 | } -------------------------------------------------------------------------------- /src/app/components/profile/profile.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 | 14 | 15 | 16 |
17 |
18 | 19 | 20 | 21 |
22 |
-------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | 36 | # e2e 37 | /e2e/*.js 38 | /e2e/*.map 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | /.vs 44 | -------------------------------------------------------------------------------- /src/sass/themes/_theme.scss: -------------------------------------------------------------------------------- 1 | @import '~@angular/material/theming'; 2 | @include mat-core(); 3 | 4 | // Define theme defaults 5 | $app-default: mat-palette($mat-blue, 500); 6 | $app-default-accent: mat-palette($mat-blue-grey, 900); 7 | $app-default-warn: mat-palette($mat-red, 800); 8 | 9 | // Build theme 10 | $theme: mat-light-theme($app-default, $app-default-accent, $app-default-warn); 11 | 12 | // Include custom theme 13 | @include angular-material-theme($theme); 14 | 15 | // Get colors from theme 16 | $accent: map-get($theme, accent); 17 | $primary: map-get($theme, primary); 18 | 19 | $accent-color: mat-color($accent); 20 | $primary-color: mat-color($primary); -------------------------------------------------------------------------------- /src/app/components/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HomeComponent } from './home.component'; 4 | 5 | describe('HomeComponent', () => { 6 | let component: HomeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ HomeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HomeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/login/login.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoginComponent } from './login.component'; 4 | 5 | describe('LoginComponent', () => { 6 | let component: LoginComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LoginComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LoginComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/sass/partials/_login.scss: -------------------------------------------------------------------------------- 1 | .login-container { 2 | display: flex; 3 | justify-content: center; 4 | 5 | .mat-form-field { 6 | width: 300px; 7 | } 8 | 9 | .center { 10 | padding-top: 40px; 11 | text-align: center; 12 | } 13 | 14 | button{ 15 | float: right; 16 | min-width: 120px; 17 | } 18 | 19 | input:-webkit-autofill, 20 | input:-webkit-autofill:hover, 21 | input:-webkit-autofill:focus, 22 | input:-webkit-autofill:active { 23 | -webkit-transition: "color 9999s ease-out, background-color 9999s ease-out"; 24 | transition: "color 9999s ease-out, background-color 9999s ease-out"; 25 | -webkit-transition-delay: 9999s; 26 | transition-delay: 9999s 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/app/components/layout/base/layout.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LayoutComponent } from './layout.component'; 4 | 5 | describe('LayoutComponent', () => { 6 | let component: LayoutComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LayoutComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LayoutComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/profile/profile.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ProfileComponent } from './profile.component'; 4 | 5 | describe('ProfileComponent', () => { 6 | let component: ProfileComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ProfileComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ProfileComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/login/login.component.html: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | -------------------------------------------------------------------------------- /src/app/components/settings/settings.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SettingsComponent } from './settings.component'; 4 | 5 | describe('SettingsComponent', () => { 6 | let component: SettingsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ SettingsComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SettingsComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/users/list/user-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { UserListComponent } from './user-list.component'; 4 | 5 | describe('UserListComponent', () => { 6 | let component: UserListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ UserListComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(UserListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/layouts/main-layout/main-layout.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { MainLayoutComponent } from './main-layout.component'; 4 | 5 | describe('MainLayoutComponent', () => { 6 | let component: MainLayoutComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ MainLayoutComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(MainLayoutComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/layout/typography/typography.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TypographyComponent } from './typography.component'; 4 | 5 | describe('TypographyComponent', () => { 6 | let component: TypographyComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ TypographyComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(TypographyComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/users/details/user-details.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { UserDetailsComponent } from './user-details.component'; 4 | 5 | describe('UserDetailsComponent', () => { 6 | let component: UserDetailsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ UserDetailsComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(UserDetailsComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/layouts/login-layout/login-layout.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoginLayoutComponent } from './login-layout.component'; 4 | 5 | describe('LoginLayoutComponent', () => { 6 | let component: LoginLayoutComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LoginLayoutComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LoginLayoutComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/layout/alerts-layout/alerts-layout.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AlertsLayoutComponent } from './alerts-layout.component'; 4 | 5 | describe('AlertsLayoutComponent', () => { 6 | let component: AlertsLayoutComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ AlertsLayoutComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(AlertsLayoutComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/dialogs/confirm-dialog/confirm-dialog.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ConfirmDialogComponent } from './confirm-dialog.component'; 4 | 5 | describe('ConfirmDialogComponent', () => { 6 | let component: ConfirmDialogComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ConfirmDialogComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ConfirmDialogComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/layout/buttons-layout/buttons-layout.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ButtonsLayoutComponent } from './buttons-layout.component'; 4 | 5 | describe('ButtonsLayoutComponent', () => { 6 | let component: ButtonsLayoutComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ButtonsLayoutComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ButtonsLayoutComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /src/sass/components/_lists.scss: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // Lists 3 | ////////////////////////////////////////////////////////////////////////////// 4 | 5 | dl { 6 | &.dl-horizontal { 7 | width: 100%; 8 | overflow: hidden; 9 | padding: 0; 10 | margin: 0; 11 | line-height: 1.5; 12 | font-size: 1em; 13 | 14 | dt { 15 | @media (min-width: 768px) { 16 | float: left; 17 | width: 140px; 18 | clear: left; 19 | } 20 | 21 | overflow: hidden; 22 | text-overflow: ellipsis; 23 | white-space: nowrap; 24 | font-weight: 700; 25 | } 26 | 27 | dd { 28 | margin-left: 0; 29 | margin-bottom: .5rem; 30 | 31 | @media (min-width: 768px) { 32 | margin-left: 160px; 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/app/components/users/shared/create-edit-user/create-edit-user.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CreateEditUserComponent } from './create-edit-user.component'; 4 | 5 | describe('CreateEditUserComponent', () => { 6 | let component: CreateEditUserComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CreateEditUserComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CreateEditUserComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/layout/typography/typography.component.html: -------------------------------------------------------------------------------- 1 |

Typography

2 |

Heading 1

3 |

Heading 2

4 |

Heading 3

5 |

Heading 4

6 |

7 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent gravida ut odio id sollicitudin. Aenean suscipit cursus tortor, non tempor magna molestie vehicula. Fusce efficitur ipsum a aliquam condimentum. In auctor dolor vel condimentum ultricies. Proin porta elementum dui at suscipit. Donec convallis euismod lectus, non venenatis ligula. Morbi at enim risus. Etiam id diam mi. Sed bibendum fermentum velit, sed congue massa. Integer sagittis maximus magna ut maximus. Nullam commodo fermentum augue, id commodo odio commodo in. Praesent viverra eros a tempus luctus. Proin blandit blandit mollis. Cras sed eros magna. Fusce mollis enim nulla, vel efficitur urna varius et. Ut in tincidunt sem. 8 |

-------------------------------------------------------------------------------- /src/sass/base/_typography.scss: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // Headings 3 | ////////////////////////////////////////////////////////////////////////////// 4 | 5 | h1, h2{ 6 | font-family: $heading-font-family; 7 | font-weight: 300; 8 | } 9 | 10 | .title{ 11 | margin-top: 0; 12 | } 13 | 14 | 15 | ////////////////////////////////////////////////////////////////////////////// 16 | // Links 17 | ////////////////////////////////////////////////////////////////////////////// 18 | 19 | a { 20 | color: $primary-color; 21 | text-decoration: none; 22 | transition: color 0.2s; 23 | 24 | &:hover { 25 | color: $accent-color; 26 | text-decoration: none; 27 | } 28 | } 29 | 30 | .mat-menu-content { 31 | .mat-card { 32 | padding: 10px 24px; 33 | 34 | .mat-card-title { 35 | font-size: 18px; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/app/components/users/shared/create-edit-user/create-edit-user.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 |
11 | 12 |
13 | 14 | 15 | 16 |
17 |
18 | 19 |
20 | 23 | 26 | 29 |
30 | -------------------------------------------------------------------------------- /src/sass/utils/_margins.scss: -------------------------------------------------------------------------------- 1 | $spaceamounts: (0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 100); 2 | 3 | @mixin generate-margin-bottom() { 4 | @each $space in $spaceamounts { 5 | @if $space == 0 { 6 | .margin-bottom-#{$space} { 7 | margin-bottom: #{$space} !important; 8 | } 9 | } 10 | @else { 11 | .margin-bottom-#{$space} { 12 | margin-bottom: #{$space}px !important; 13 | } 14 | } 15 | } 16 | } 17 | 18 | @mixin generate-margin-top() { 19 | @each $space in $spaceamounts { 20 | @if $space == 0 { 21 | .margin-top-#{$space} { 22 | margin-top: #{$space} !important; 23 | } 24 | } 25 | @else { 26 | .margin-top-#{$space} { 27 | margin-top: #{$space}px !important; 28 | } 29 | } 30 | } 31 | } 32 | 33 | @include generate-margin-bottom(); 34 | @include generate-margin-top(); -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular/cli'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular/cli/plugins/karma') 14 | ], 15 | client:{ 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | reports: [ 'html', 'lcovonly' ], 20 | fixWebpackSourcePaths: true 21 | }, 22 | angularCli: { 23 | environment: 'dev' 24 | }, 25 | reporters: ['progress', 'kjhtml'], 26 | port: 9876, 27 | colors: true, 28 | logLevel: config.LOG_INFO, 29 | autoWatch: true, 30 | browsers: ['Chrome'], 31 | singleRun: false 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /src/app/components/settings/settings.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Toolbar layout

3 | Full width 4 |
5 | 6 |
7 |

Theme ({{ selectedTheme.name }})

8 | 15 |
16 | 17 | 18 | fiber_manual_record 19 | 20 | 21 |
22 |
23 | -------------------------------------------------------------------------------- /src/app/components/settings/settings.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { MatSnackBar } from '@angular/material'; 3 | import 'rxjs/add/operator/filter'; 4 | 5 | import { ThemeService } from '../../services'; 6 | 7 | @Component({ 8 | selector: 'app-settings', 9 | templateUrl: './settings.component.html', 10 | providers: [ ThemeService ] 11 | }) 12 | export class SettingsComponent { 13 | 14 | themes: Array = []; 15 | 16 | selectedTheme: any; 17 | isFullWidth: boolean = true; 18 | 19 | constructor(private themeService: ThemeService, private snackBar: MatSnackBar) { 20 | this.themes = themeService.themes; 21 | this.selectedTheme = themeService.currentTheme(); 22 | 23 | this.isFullWidth = themeService.isFullWidth(); 24 | } 25 | 26 | onThemeSelected(theme: any){ 27 | this.themeService.setTheme(theme); 28 | 29 | this.snackBar.open(`Theme changed to "${theme.name}"`, null, { 30 | duration: 3000 31 | }); 32 | } 33 | 34 | setFullWidth(isFullWidth: boolean){ 35 | this.themeService.setFullWidth(isFullWidth); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/app/components/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | describe('AppComponent', () => { 4 | beforeEach(async(() => { 5 | TestBed.configureTestingModule({ 6 | declarations: [ 7 | AppComponent 8 | ], 9 | }).compileComponents(); 10 | })); 11 | it('should create the app', async(() => { 12 | const fixture = TestBed.createComponent(AppComponent); 13 | const app = fixture.debugElement.componentInstance; 14 | expect(app).toBeTruthy(); 15 | })); 16 | it(`should have as title 'app'`, async(() => { 17 | const fixture = TestBed.createComponent(AppComponent); 18 | const app = fixture.debugElement.componentInstance; 19 | expect(app.title).toEqual('app'); 20 | })); 21 | it('should render title in a h1 tag', async(() => { 22 | const fixture = TestBed.createComponent(AppComponent); 23 | fixture.detectChanges(); 24 | const compiled = fixture.debugElement.nativeElement; 25 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); 26 | })); 27 | }); 28 | -------------------------------------------------------------------------------- /src/app/components/layout/alerts-layout/alerts-layout.component.html: -------------------------------------------------------------------------------- 1 |

Alerts

2 |
3 |
4 | Error! This is danger alert! 5 |
6 | 7 |
8 | Info! This is info alert! 9 |
10 | 11 |
12 | Success! This is success alert! 13 |
14 | 15 |
16 | Warning! This is warning alert! 17 |
18 |
19 | 20 |

Callouts

21 |
22 |
23 |

Error!

This is danger callout! 24 |
25 | 26 |
27 |

Info!

This is info callout! 28 |
29 | 30 |
31 |

Warning!

This is warning callout! 32 |
33 | 34 |
35 |

Success!

This is success callout! 36 |
37 |
38 | -------------------------------------------------------------------------------- /compilerconfig.json.defaults: -------------------------------------------------------------------------------- 1 | { 2 | "compilers": { 3 | "less": { 4 | "autoPrefix": "", 5 | "cssComb": "none", 6 | "ieCompat": true, 7 | "strictMath": false, 8 | "strictUnits": false, 9 | "relativeUrls": true, 10 | "rootPath": "", 11 | "sourceMapRoot": "", 12 | "sourceMapBasePath": "", 13 | "sourceMap": false 14 | }, 15 | "sass": { 16 | "includePath": "", 17 | "indentType": "space", 18 | "indentWidth": 2, 19 | "outputStyle": "nested", 20 | "Precision": 5, 21 | "relativeUrls": true, 22 | "sourceMapRoot": "", 23 | "sourceMap": false 24 | }, 25 | "stylus": { 26 | "sourceMap": false 27 | }, 28 | "babel": { 29 | "sourceMap": false 30 | }, 31 | "coffeescript": { 32 | "bare": false, 33 | "runtimeMode": "node", 34 | "sourceMap": false 35 | } 36 | }, 37 | "minifiers": { 38 | "css": { 39 | "enabled": true, 40 | "termSemicolons": true, 41 | "gzip": false 42 | }, 43 | "javascript": { 44 | "enabled": true, 45 | "termSemicolons": true, 46 | "gzip": false 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/long-stack-trace-zone'; 4 | import 'zone.js/dist/proxy.js'; 5 | import 'zone.js/dist/sync-test'; 6 | import 'zone.js/dist/jasmine-patch'; 7 | import 'zone.js/dist/async-test'; 8 | import 'zone.js/dist/fake-async-test'; 9 | import { getTestBed } from '@angular/core/testing'; 10 | import { 11 | BrowserDynamicTestingModule, 12 | platformBrowserDynamicTesting 13 | } from '@angular/platform-browser-dynamic/testing'; 14 | 15 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. 16 | declare const __karma__: any; 17 | declare const require: any; 18 | 19 | // Prevent Karma from running prematurely. 20 | __karma__.loaded = function () {}; 21 | 22 | // First, initialize the Angular testing environment. 23 | getTestBed().initTestEnvironment( 24 | BrowserDynamicTestingModule, 25 | platformBrowserDynamicTesting() 26 | ); 27 | // Then we find all the tests. 28 | const context = require.context('./', true, /\.spec\.ts$/); 29 | // And load the modules. 30 | context.keys().map(context); 31 | // Finally, start Karma to run the tests. 32 | __karma__.start(); 33 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Material Boilerplate 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 38 | 39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | -------------------------------------------------------------------------------- /src/sass/components/_table.scss: -------------------------------------------------------------------------------- 1 | @import '../themes/_theme.scss'; 2 | 3 | .table { 4 | width: 100%; 5 | max-width: 100%; 6 | border-spacing: 0; 7 | border-collapse: collapse; 8 | 9 | &>caption+thead>tr:first-child>td, 10 | &>caption+thead>tr:first-child>th, 11 | &>colgroup+thead>tr:first-child>td, 12 | &>colgroup+thead>tr:first-child>th, 13 | &>thead:first-child>tr:first-child>td, 14 | &>thead:first-child>tr:first-child>th { 15 | border-top: 0; 16 | text-align: left; 17 | } 18 | 19 | &>tbody>tr>td, 20 | &>tbody>tr>th, 21 | &>tfoot>tr>td, 22 | &>tfoot>tr>th, 23 | &>thead>tr>td, 24 | &>thead>tr>th { 25 | padding: 12px 8px; 26 | line-height: 1.4em; 27 | vertical-align: top; 28 | } 29 | 30 | tr{ 31 | border-bottom: 1px solid $light-border-color; 32 | } 33 | 34 | &.table-bordered{ 35 | border: 1px solid $light-border-color; 36 | } 37 | } 38 | 39 | @media (max-width: 991px){ 40 | .table-responsive { 41 | display: block; 42 | width: 100%; 43 | overflow-x: auto; 44 | overflow-y: hidden; 45 | 46 | tr{ 47 | td{ 48 | white-space: nowrap; 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/app/components/users/details/user-details.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | import { MatDialog } from '@angular/material'; 4 | import { UserService } from '../services'; 5 | import { ConfirmDialogComponent } from '../../dialogs/confirm-dialog/confirm-dialog.component'; 6 | 7 | @Component({ 8 | selector: 'app-user-details', 9 | templateUrl: './user-details.component.html', 10 | providers: [ UserService ] 11 | }) 12 | export class UserDetailsComponent implements OnInit { 13 | user: any; 14 | 15 | constructor(private route: ActivatedRoute, private service: UserService, private dialog: MatDialog) { } 16 | 17 | ngOnInit() { 18 | this.route.params.subscribe(params => { 19 | let id = params['id']; 20 | this.getUser(id); 21 | }); 22 | } 23 | 24 | private getUser(id: any){ 25 | this.service.getUser(id).subscribe(data => this.user = data); 26 | } 27 | 28 | onDelete(): void { 29 | let dialogRef = this.dialog.open(ConfirmDialogComponent, { 30 | data: { title: 'Delete user', message: 'Are you sure you want to delete selected user?' } 31 | }); 32 | 33 | dialogRef.afterClosed().subscribe(result => { 34 | console.log('The dialog was closed', result); 35 | }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/app/components/shared/toolbar/toolbar.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | {{ header }} 11 | 12 | 13 |
14 | 15 | 18 | 19 | 20 | 21 | Profile & Settings 22 | john.doe@example.com 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
32 | -------------------------------------------------------------------------------- /src/app/components/users/shared/create-edit-user/create-edit-user.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | 4 | import { UserService } from '../../services'; 5 | import { User } from '../../models'; 6 | 7 | export enum EditMode { 8 | Create = 0, 9 | Edit = 1 10 | } 11 | 12 | @Component({ 13 | selector: 'app-create-edit-user', 14 | templateUrl: './create-edit-user.component.html', 15 | providers: [ UserService ] 16 | }) 17 | export class CreateEditUserComponent implements OnInit { 18 | user: User; 19 | editMode: EditMode = EditMode.Create; 20 | 21 | constructor(private route: ActivatedRoute, private service: UserService) { } 22 | 23 | ngOnInit() { 24 | this.route.params.subscribe(params => { 25 | let id = params['id']; 26 | if(id){ 27 | this.editMode = EditMode.Edit; 28 | this.getUser(id); 29 | } 30 | else{ 31 | this.editMode = EditMode.Create; 32 | this.user = new User(); 33 | } 34 | }); 35 | 36 | console.log('EditMode', EditMode[this.editMode], this.editMode); 37 | } 38 | 39 | private getUser(id: any){ 40 | this.service.getUser(id).subscribe(data => this.user = data); 41 | } 42 | 43 | onSave(){ 44 | console.log(this.user); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/sass/themes/_light-theme.scss: -------------------------------------------------------------------------------- 1 | @import '~@angular/material/theming'; 2 | @include mat-core(); 3 | 4 | @import '../base/_variables.scss'; 5 | 6 | $primary-light: mat-palette($mat-blue); 7 | $accent-light: mat-palette($mat-light-blue); 8 | $warn-light: mat-palette($mat-red); 9 | 10 | .light-theme{ 11 | 12 | $light-theme: mat-light-theme($primary-light, $accent-light, $warn-light); 13 | @include angular-material-theme($light-theme); 14 | 15 | &.theme-indicator{ 16 | color: #cccccc!important; 17 | } 18 | 19 | .mat-toolbar{ 20 | background: #03A9F4!important; 21 | color: #ffffff!important; 22 | } 23 | 24 | .mat-sidenav{ 25 | 26 | background-color: #fafafa!important; 27 | 28 | .sidenav { 29 | a{ 30 | color: currentColor!important; 31 | 32 | &.active, 33 | &.active:hover, 34 | &.active:focus, 35 | &.active:active{ 36 | background-color: #c5c5c59f!important; 37 | } 38 | } 39 | } 40 | } 41 | 42 | /////////////////////////////////////////////// 43 | // Tables 44 | ////////////////////////////////////////////// 45 | .table{ 46 | tr{ 47 | border-bottom: 1px solid $light-border-color; 48 | } 49 | 50 | &.table-bordered{ 51 | border: 1px solid $light-border-color; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular Material Boilerplate 2 | 3 | Boilerplate Angular 4 project with initial setup for angular application with [Material UI](https://material.angular.io/) 4 | 5 | ## Demo 6 | [**VIEW LIVE DEMO**](https://aronium.github.io/angular-material-boilerplate/) 7 | 8 | ## Dev Notes 9 | 10 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.4.5. 11 | 12 | ## Development server 13 | 14 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 15 | 16 | ## Code scaffolding 17 | 18 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 19 | 20 | ## Build 21 | 22 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build. 23 | 24 | ## Running unit tests 25 | 26 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 27 | 28 | ## Running end-to-end tests 29 | 30 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 31 | 32 | ## Further help 33 | 34 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 35 | -------------------------------------------------------------------------------- /src/app/components/shared/navbar/navbar.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | dashboard 6 | Dashboard 7 | 8 | 9 | people 10 | Users 11 | 12 | 27 | 28 |
29 | -------------------------------------------------------------------------------- /src/sass/themes/_dark-theme.scss: -------------------------------------------------------------------------------- 1 | @import '~@angular/material/theming'; 2 | @include mat-core(); 3 | 4 | $table-border-color: #2F3030; 5 | 6 | $primary-dark: mat-palette($mat-blue, 700); 7 | $accent-dark: mat-palette($mat-light-blue, 600); 8 | $warn-dark: mat-palette($mat-red); 9 | 10 | .dark-theme { 11 | 12 | $dark-theme: mat-dark-theme($primary-dark, $accent-dark, $warn-dark); 13 | @include angular-material-theme($dark-theme); 14 | 15 | &.theme-indicator { 16 | color: #777777 !important; 17 | } 18 | 19 | a { 20 | color: #ffffff; 21 | text-decoration: none; 22 | transition: color 0.2s; 23 | 24 | &:hover { 25 | color: #dadada; 26 | text-decoration: none; 27 | } 28 | } 29 | 30 | .mat-sidenav-container { 31 | .mat-sidenav { 32 | background: #434443 !important; 33 | 34 | .sidenav { 35 | 36 | a { 37 | &.active, 38 | &.active:hover, 39 | &.active:focus, 40 | &.active:active { 41 | background-color: #009CE4!important; 42 | color: #ffffff; 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | /////////////////////////////////////////////// 50 | // Tables 51 | ////////////////////////////////////////////// 52 | .table { 53 | tr { 54 | border-bottom: 1px solid $table-border-color; 55 | } 56 | 57 | &.table-bordered { 58 | border-bottom: 1px solid $table-border-color; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /.angular-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "project": { 4 | "name": "aronium-inside" 5 | }, 6 | "apps": [ 7 | { 8 | "root": "src", 9 | "outDir": "dist", 10 | "assets": [ 11 | "assets", 12 | "favicon.ico" 13 | ], 14 | "index": "index.html", 15 | "main": "main.ts", 16 | "polyfills": "polyfills.ts", 17 | "test": "test.ts", 18 | "tsconfig": "tsconfig.app.json", 19 | "testTsconfig": "tsconfig.spec.json", 20 | "prefix": "app", 21 | "styles": [ 22 | "styles.scss" 23 | ], 24 | "scripts": [ 25 | "../node_modules/chart.js/dist/Chart.bundle.min.js" 26 | ], 27 | "environmentSource": "environments/environment.ts", 28 | "environments": { 29 | "dev": "environments/environment.ts", 30 | "prod": "environments/environment.prod.ts" 31 | } 32 | } 33 | ], 34 | "e2e": { 35 | "protractor": { 36 | "config": "./protractor.conf.js" 37 | } 38 | }, 39 | "lint": [ 40 | { 41 | "project": "src/tsconfig.app.json", 42 | "exclude": "**/node_modules/**" 43 | }, 44 | { 45 | "project": "src/tsconfig.spec.json", 46 | "exclude": "**/node_modules/**" 47 | }, 48 | { 49 | "project": "e2e/tsconfig.e2e.json", 50 | "exclude": "**/node_modules/**" 51 | } 52 | ], 53 | "test": { 54 | "karma": { 55 | "config": "./karma.conf.js" 56 | } 57 | }, 58 | "defaults": { 59 | "styleExt": "css", 60 | "component": {} 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/sass/themes/_mixed-theme.scss: -------------------------------------------------------------------------------- 1 | @import '~@angular/material/theming'; 2 | @include mat-core(); 3 | 4 | @import '../base/_variables.scss'; 5 | 6 | $mixed-primary: mat-palette($mat-blue, 700); 7 | $mixed-accent: mat-palette($mat-light-blue, 700); 8 | $app-light-warn: mat-palette($mat-red, A700); 9 | 10 | .mixed-theme{ 11 | 12 | $mixed-theme: mat-light-theme($mixed-primary, $mixed-accent, $app-light-warn); 13 | @include angular-material-theme($mixed-theme); 14 | 15 | &.theme-indicator{ 16 | color: rgb(3, 151, 236)!important; 17 | } 18 | 19 | .mat-sidenav-container{ 20 | .mat-toolbar{ 21 | background: white!important; 22 | color: #444444!important; 23 | border-bottom: 1px solid $light-border-color; 24 | 25 | .logo{ 26 | background-position-y: 0!important; 27 | } 28 | } 29 | 30 | .mat-sidenav{ 31 | background-color: #0288D1!important; 32 | 33 | .sidenav { 34 | a{ 35 | color: #ffffff!important; 36 | 37 | &.active, 38 | &.active:hover, 39 | &.active:focus, 40 | &.active:active{ 41 | background-color: #0277BD!important; 42 | color: #ffffff!important; 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | &.theme-indicator{ 50 | color: #0288D1!important; 51 | } 52 | 53 | /////////////////////////////////////////////// 54 | // Tables 55 | ////////////////////////////////////////////// 56 | .table{ 57 | tr{ 58 | border-bottom: 1px solid $light-border-color; 59 | } 60 | 61 | &.table-bordered{ 62 | border: 1px solid $light-border-color; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng-test", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "ng": "ng", 7 | "start": "ng serve", 8 | "build": "ng build", 9 | "test": "ng test", 10 | "lint": "ng lint", 11 | "e2e": "ng e2e" 12 | }, 13 | "private": true, 14 | "dependencies": { 15 | "@angular/animations": "^5.0.3", 16 | "@angular/cdk": "^5.0.0-rc.1", 17 | "@angular/common": "^5.0.0", 18 | "@angular/compiler": "^5.0.0", 19 | "@angular/core": "^5.0.0", 20 | "@angular/forms": "^5.0.0", 21 | "@angular/http": "^5.0.0", 22 | "@angular/material": "^5.0.0-rc.1", 23 | "@angular/platform-browser": "^5.0.0", 24 | "@angular/platform-browser-dynamic": "^5.0.0", 25 | "@angular/router": "^5.0.0", 26 | "angular-svg-round-progressbar": "^1.1.1", 27 | "chart.js": "^2.7.0", 28 | "core-js": "^2.4.1", 29 | "hammerjs": "^2.0.8", 30 | "ng2-charts": "^1.6.0", 31 | "ngx-progressbar": "^2.1.1", 32 | "rxjs": "^5.5.2", 33 | "zone.js": "^0.8.14" 34 | }, 35 | "devDependencies": { 36 | "@angular/cli": "^1.6.4", 37 | "@angular/compiler-cli": "^5.0.0", 38 | "@angular/language-service": "^5.0.0", 39 | "@types/jasmine": "~2.5.53", 40 | "@types/jasminewd2": "~2.0.2", 41 | "@types/node": "~6.0.60", 42 | "codelyzer": "^4.0.1", 43 | "jasmine-core": "~2.6.2", 44 | "jasmine-spec-reporter": "~4.1.0", 45 | "karma": "~1.7.0", 46 | "karma-chrome-launcher": "~2.1.1", 47 | "karma-cli": "~1.0.1", 48 | "karma-coverage-istanbul-reporter": "^1.2.1", 49 | "karma-jasmine": "~1.1.0", 50 | "karma-jasmine-html-reporter": "^0.2.2", 51 | "protractor": "~5.1.2", 52 | "ts-node": "~3.2.0", 53 | "tslint": "~5.7.0", 54 | "typescript": "~2.4.2" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/app/components/users/list/user-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | import { UserService } from '../services'; 4 | 5 | @Component({ 6 | selector: 'app-user-list', 7 | templateUrl: './user-list.component.html', 8 | providers: [UserService] 9 | }) 10 | export class UserListComponent implements OnInit { 11 | 12 | private allUsersChecked: boolean = false; 13 | 14 | users: Array; 15 | isAdvancedSearchEnabled: boolean = false; 16 | email:string; 17 | startDate: Date = null; 18 | endDate:Date = null; 19 | state:string; 20 | states = [ 21 | 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 22 | 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 23 | 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 24 | 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 25 | 'New York', 'North Carolina', 'North Dakota', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 26 | 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 27 | 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' 28 | ]; 29 | 30 | constructor(private service: UserService) { } 31 | 32 | ngOnInit() { 33 | this.loadUsers(); 34 | } 35 | 36 | private loadUsers(): void{ 37 | this.service.getUsers().subscribe(data => { 38 | this.users = data 39 | }); 40 | } 41 | 42 | onRefresh(){ 43 | this.users = null; 44 | 45 | this.loadUsers(); 46 | } 47 | 48 | checkAll() { 49 | this.allUsersChecked = !this.allUsersChecked; 50 | for (let i in this.users) { 51 | this.users[i].selected = this.allUsersChecked; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/app/components/users/details/user-details.component.html: -------------------------------------------------------------------------------- 1 | 4 | 7 | 10 | 11 |
12 | 13 | {{ user.name }} 14 | Username: {{ user.username }} 15 | 16 |
17 |
Name
18 |
{{ user.name }}
19 |
Username
20 |
{{ user.username }}
21 |
Email
22 |
{{ user.email }}
23 |
Phone
24 |
{{ user.phone }}
25 |
Web
26 |
{{ user.website }}
27 |
28 |
29 |
30 |
31 | 32 |
33 | 34 | Company 35 | 36 |
37 |
Company name
38 |
{{ user.company.name }}
39 | 40 |
Additional data
41 |
{{ user.company.catchPhrase }}
42 | 43 |
Product search type 44 |
45 |
{{ user.company.bs }}
46 |
47 |
48 |
49 |
50 | 51 | 54 | -------------------------------------------------------------------------------- /src/app/components/layout/buttons-layout/buttons-layout.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | Flat Buttons 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | Link 12 |
13 |
14 |
15 |
16 | 17 |
18 | 19 | Raised Buttons 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | Link 28 |
29 |
30 |
31 |
32 | 33 |
34 | 35 | Fab Buttons 36 | 37 | 40 | 43 | 46 | 49 | 50 | 51 |
-------------------------------------------------------------------------------- /src/app/services/http.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient, HttpHeaders } from '@angular/common/http'; 3 | import { Observable } from 'rxjs/Rx'; 4 | import { Router } from '@angular/router'; 5 | import { environment } from '../../environments/environment'; 6 | 7 | import 'rxjs/Rx'; 8 | 9 | @Injectable() 10 | export class HttpService { 11 | 12 | private baseUrl: string; 13 | 14 | constructor(private http: HttpClient, private router: Router) { 15 | this.baseUrl = environment.baseUrl; 16 | } 17 | 18 | private getHeaders(): HttpHeaders { 19 | let headers = new HttpHeaders().set('Content-Type', 'application/json'); 20 | 21 | let user = localStorage.getItem('user'); 22 | 23 | if (user) { 24 | // HttpHeaders are immutable, set() method returns new instance of HttpHeaders 25 | headers = headers.set('Authorization', `Bearer ${JSON.parse(user).token}`); 26 | } 27 | 28 | return headers; 29 | } 30 | 31 | private onError(error: any): Promise { 32 | if (error.status === 401 || error.status === 403) { 33 | this.router.navigate(['/login']); 34 | } 35 | return Promise.reject(error); 36 | } 37 | 38 | /** 39 | * Executes GET request for specified url. 40 | * @param url Url to execute. 41 | */ 42 | get(url: string): Observable { 43 | return this.http.get(`${this.baseUrl}${url}`, { 44 | headers: this.getHeaders() 45 | }).catch(error => this.onError(error)); 46 | } 47 | 48 | /** 49 | * Executes POST request with specified url and data 50 | * @param url Request Url. 51 | * @param data Post data. 52 | */ 53 | post(url: string, data: any): Observable { 54 | return this.http.post(`${this.baseUrl}${url}`, data, { 55 | headers: this.getHeaders() 56 | }).catch(error => this.onError(error)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/sass/themes/_black-theme.scss: -------------------------------------------------------------------------------- 1 | @import '~@angular/material/theming'; 2 | @include mat-core(); 3 | 4 | $toolbar-border-color: #424242; 5 | 6 | $primary-black: mat-palette($mat-blue-grey, 600); 7 | $accent-black: mat-palette($mat-blue-grey, 800); 8 | $warn-black: mat-palette($mat-red, 900); 9 | 10 | .black-theme { 11 | 12 | $black-theme: mat-dark-theme($primary-black, $accent-black, $warn-black); 13 | @include angular-material-theme($black-theme); 14 | 15 | &.theme-indicator { 16 | color: #111111 !important; 17 | } 18 | 19 | .mat-sidenav-container { 20 | background: #252525 !important; 21 | 22 | .mat-toolbar { 23 | background: #222222 !important; 24 | border-bottom: 1px solid $toolbar-border-color; 25 | } 26 | 27 | .mat-sidenav-content { 28 | 29 | a { 30 | color: #ffffff; 31 | text-decoration: none; 32 | transition: color 0.2s; 33 | 34 | &:hover { 35 | color: #dadada; 36 | text-decoration: none; 37 | } 38 | } 39 | 40 | .mat-card { 41 | background: #313131 !important; 42 | 43 | .info-card-icon{ 44 | background-color: inherit !important; 45 | } 46 | } 47 | } 48 | 49 | .mat-sidenav { 50 | background: #222222 !important; 51 | border-right: 1px solid $toolbar-border-color; 52 | 53 | .sidenav { 54 | a { 55 | color: #ffffff !important; 56 | 57 | &.active, 58 | &.active:hover, 59 | &.active:focus, 60 | &.active:active { 61 | background: #1d1c1c !important; 62 | color: #ffffff !important; 63 | } 64 | } 65 | } 66 | } 67 | } 68 | 69 | /////////////////////////////////////////////// 70 | // Tables 71 | ////////////////////////////////////////////// 72 | .table{ 73 | tr{ 74 | border-bottom: 1px solid #262827; 75 | } 76 | 77 | &.table-bordered{ 78 | border: 1px solid #262827; 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /src/sass/themes/_snow-white-theme.scss: -------------------------------------------------------------------------------- 1 | @import '~@angular/material/theming'; 2 | @include mat-core(); 3 | 4 | @import '../base/_variables.scss'; 5 | 6 | $primary-white: mat-palette($mat-blue, 700); 7 | $accent-white: mat-palette($mat-light-blue, 600); 8 | $warn-white: mat-palette($mat-red); 9 | 10 | $foreground: #444444; 11 | 12 | .snow-white-theme{ 13 | 14 | $snow-theme: mat-light-theme($primary-white, $accent-white, $warn-white); 15 | @include angular-material-theme($snow-theme); 16 | 17 | &.theme-indicator{ 18 | color: #ffffff!important; 19 | border-color: #efefef!important; 20 | } 21 | 22 | .mat-sidenav-container{ 23 | background: white!important; 24 | 25 | .mat-toolbar{ 26 | background: white!important; 27 | color: $foreground!important; 28 | border-bottom: 1px solid $light-border-color; 29 | 30 | .logo{ 31 | background-position-y: 0!important; 32 | } 33 | } 34 | 35 | .mat-sidenav-content{ 36 | .mat-card{ 37 | &.info-card{ 38 | background-color: inherit !important; 39 | color: inherit !important; 40 | 41 | .info-card-icon{ 42 | background-color: inherit !important; 43 | } 44 | } 45 | } 46 | } 47 | 48 | .mat-sidenav{ 49 | border-right: 1px solid $light-border-color; 50 | background: white!important; 51 | 52 | .sidenav { 53 | a{ 54 | color: #444444!important; 55 | 56 | &.active, 57 | &.active:hover, 58 | &.active:focus, 59 | &.active:active{ 60 | background-color: rgba(0,0,0,0.1)!important; 61 | color: #111111!important; 62 | } 63 | } 64 | } 65 | } 66 | } 67 | 68 | /////////////////////////////////////////////// 69 | // Tables 70 | ////////////////////////////////////////////// 71 | .table{ 72 | tr{ 73 | border-bottom: 1px solid $light-border-color; 74 | } 75 | 76 | &.table-bordered{ 77 | border: 1px solid $light-border-color; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/app/components/shared/toolbar/toolbar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; 2 | import { NavigationEnd, Router, ActivatedRoute } from '@angular/router'; 3 | import { forEach } from '@angular/router/src/utils/collection'; 4 | import { Title } from '@angular/platform-browser'; 5 | 6 | @Component({ 7 | selector: 'app-toolbar', 8 | templateUrl: './toolbar.component.html' 9 | }) 10 | export class ToolbarComponent implements OnInit { 11 | 12 | private sub: any; 13 | private defaultTitle: string; 14 | 15 | @Input() 16 | header: string; 17 | 18 | @Output() 19 | toggleMenu = new EventEmitter(); 20 | 21 | constructor(private router: Router, 22 | private route: ActivatedRoute, 23 | private titleService: Title) { } 24 | 25 | /** 26 | * Dispatch toggleMenu event. 27 | */ 28 | onToggleMenu() { 29 | this.toggleMenu.emit(); 30 | } 31 | 32 | ngOnInit() { 33 | // Use default header as the document title or a fallback for toolbar title 34 | this.defaultTitle = this.header; 35 | 36 | // Get initial title on page load 37 | this.getPageTitle(); 38 | 39 | this.sub = this.router.events 40 | .filter(event => event instanceof NavigationEnd) 41 | .subscribe((event: NavigationEnd) => { 42 | this.getPageTitle(); 43 | }); 44 | } 45 | 46 | private getPageTitle(): void { 47 | let parentRouteTitle; 48 | let snapshot = this.route.snapshot; 49 | let activated = this.route.firstChild; 50 | if (activated != null) { 51 | while (activated != null) { 52 | // Get title for the current route, if case child is missing rote data, use parent title. 53 | parentRouteTitle = snapshot.data['title'] || parentRouteTitle; 54 | 55 | snapshot = activated.snapshot; 56 | activated = activated.firstChild; 57 | } 58 | } 59 | 60 | // Set header, fallback to default title if data not set on route 61 | let title = snapshot.data['title'] || parentRouteTitle; 62 | 63 | // If any custom title is set, use it 64 | this.header = title || this.defaultTitle; 65 | 66 | // Set document title 67 | this.titleService.setTitle(title ? `${this.defaultTitle} - ${title}` : this.defaultTitle) 68 | } 69 | 70 | ngOnDestroy() { 71 | this.sub.unsubscribe(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/sass/components/_nav.scss: -------------------------------------------------------------------------------- 1 | @import '../themes/_theme.scss'; 2 | 3 | $expand-icon-size: 16px; 4 | 5 | body{ 6 | // If .full-width is not set on main container, add logo to sidenav 7 | :not(.full-width){ 8 | .sidenav{ 9 | .logo{ 10 | margin: 0 auto; 11 | margin-top: 20px; 12 | width: 100px; 13 | height: 100px; 14 | 15 | background-image: url('/assets/logos.png'); 16 | background-repeat: no-repeat; 17 | background-position-y: -90px; 18 | } 19 | } 20 | } 21 | } 22 | 23 | .mat-sidenav-container{ 24 | .mat-sidenav{ 25 | background-color: #37474C; 26 | 27 | .sidenav { 28 | width: $sidenav-width !important; 29 | 30 | .mat-icon{ 31 | height: 22px; 32 | width: 22px; 33 | font-size: 22px; 34 | } 35 | 36 | a{ 37 | font-size: 14px!important; 38 | color: #ffffff; 39 | 40 | span{ 41 | margin-left: 10px; 42 | } 43 | 44 | &.active, 45 | &.active:hover, 46 | &.active:focus, 47 | &.active:active{ 48 | background-color: $accent-color; 49 | color: #ffffff; 50 | } 51 | } 52 | 53 | ul, li{ 54 | list-style: none; 55 | padding: 0; 56 | margin: 0; 57 | 58 | .expand-icon{ 59 | transition: all 500ms ease; 60 | height: $expand-icon-size; 61 | width: $expand-icon-size; 62 | font-size: $expand-icon-size; 63 | 64 | &::after{ 65 | content: 'add'; 66 | } 67 | 68 | &.collapse{ 69 | // Using expand_more icon with rotation 70 | // -webkit-transform: rotate(-180deg); 71 | // -moz-transform: rotate(-180deg); 72 | // transform: rotate(-180deg); 73 | 74 | &::after{ 75 | content: 'remove'; 76 | } 77 | } 78 | } 79 | 80 | ul{ 81 | text-indent: 22px; 82 | 83 | &.collapsed{ 84 | display: none; 85 | 86 | // transition: max-height 0.1s; 87 | // max-height: 0; 88 | // overflow: hidden; 89 | } 90 | &.expanded{ 91 | display: block; 92 | 93 | // transition: max-height 0.5s; 94 | // max-height: 100vh; 95 | } 96 | } 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/app/components/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-home', 5 | templateUrl: './home.component.html' 6 | }) 7 | export class HomeComponent { 8 | 9 | loading: boolean = false; 10 | 11 | barChartData: Array = [[27, 33, 32, 34, 48, 42, 30, 37, 23, 33, 6, 7, 9, 17, 7, 10, 10, 10, 16, 6, 9, 18, 24, 8, 11, 10, 23, 31, 22, 26]]; 12 | barChartLabels: Array = ["Fri 01", "Sat 02", "Sun 03", "Mon 04", "Tue 05", "Wed 06", "Thu 07", "Fri 08", "Sat 09", "Sun 10", "Mon 11", "Tue 12", "Wed 13", "Thu 14", "Fri 15", "Sat 16", "Sun 17", "Mon 18", "Tue 19", "Wed 20", "Thu 21", "Fri 22", "Sat 23", "Sun 24", "Mon 25", "Tue 26", "Wed 27", "Thu 28", "Fri 29", "Sat 30"]; 13 | barChartColors = [{ backgroundColor: 'rgba(0, 156, 228, 0.80)' }] 14 | 15 | lineChartData: Array = [[10, 30, 33, 80, 87, 101, 112]]; 16 | lineChartLabels: Array = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; 17 | lineChartColors = [{ backgroundColor: 'rgba(0,0,0,0.0)', borderColor: 'rgba(92, 184, 92, 0.8)' }] 18 | 19 | versionsData: Array = [[2, 1, 2, 1, 1, 8, 2, 2, 1, 1, 1, 12, 26, 8, 17, 6, 4, 54, 34]]; 20 | versionsLabels: Array = ['0.9.5.0', '1.2.0.0', '1.3.1.0', '1.4.0.0', '1.6.0.0', '1.7.0.0', '1.7.1.0', '1.8.0.0', '1.9.0.0', '1.10.0.0', '1.10.1.1', '1.11.0.0', '1.12.0.0', '1.13.0.0', '1.13.1.0', '1.13.2.0', '1.13.3.0', '1.14.0.0', '1.14.1.0']; 21 | 22 | pieChartData: Array = [[10, 100, 154, 184, 476, 95, 133, 408, 619, 363]]; 23 | pieChartLabels: Array = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct']; 24 | pieChart2Data: Array = [[112,55]]; 25 | pieChart2Labels: Array = ['Active', 'Inactive']; 26 | pieChart2Colors: any[] = [{ backgroundColor: ['rgba(21,101,192,.8)', 'rgba(96,125,139,.7)'] }]; 27 | pieChart3Data: Array = [[95, 78]]; 28 | pieChart3Labels: Array = ['Dark', 'Light']; 29 | 30 | chartOptions = { 31 | bezierCurve: false, 32 | responsive: true, 33 | maintainAspectRatio: false, 34 | elements: { 35 | line: { 36 | tension: 0 37 | } 38 | }, 39 | legend: { 40 | display: false 41 | } 42 | }; 43 | 44 | pieChartOptions: any = { 45 | cutoutPercentage: 0, 46 | responsive: true, 47 | maintainAspectRatio: false, 48 | legend: { 49 | display: false, 50 | } 51 | }; 52 | 53 | constructor() { } 54 | 55 | onRefresh(){ 56 | this.loading = true; 57 | 58 | setTimeout(() => { 59 | this.loading = false; 60 | }, 2000); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/app/components/layout/base/layout.component.html: -------------------------------------------------------------------------------- 1 |

Flex layout

2 |
3 | 4 | .col 5 | 6 |
7 |
8 | 9 | .col 10 | 11 | 12 | .col 13 | 14 |
15 |
16 | 17 | .col 18 | 19 | 20 | .col 21 | 22 | 23 | .col 24 | 25 |
26 |
27 | 28 | .col 29 | 30 | 31 | .col 32 | 33 | 34 | .col 35 | 36 | 37 | .col 38 | 39 |
40 |
41 | 42 | .col 43 | 44 | 45 | .col 46 | 47 | 48 | .col 49 | 50 | 51 | .col 52 | 53 | 54 | .col 55 | 56 | 57 | .col 58 | 59 |
60 | 61 |

Nested flex containers

62 |

Using nesting so columns keeps the same width as flex items put directly in container, aligned to above examples.

63 |
64 |
65 | 66 | .col 67 | 68 |
69 |
70 | 71 | .col 72 | 73 | 74 | .col 75 | 76 |
77 |
78 | 79 | 80 |

Using ".col-x" classes to grow content in container

81 |
82 | 83 | .col .col-x2 84 | 85 | 86 | .col 87 | 88 |
89 |
90 | 91 | .col .col-x3 92 | 93 | 94 | .col 95 | 96 |
97 |
98 | 99 | .col .col-x4 100 | 101 | 102 | .col 103 | 104 |
-------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/weak-map'; 35 | // import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 38 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 39 | 40 | /** Evergreen browsers require these. **/ 41 | import 'core-js/es6/reflect'; 42 | import 'core-js/es7/reflect'; 43 | 44 | 45 | /** 46 | * Required to support Web Animations `@angular/platform-browser/animations`. 47 | * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation 48 | **/ 49 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 50 | 51 | 52 | 53 | /*************************************************************************************************** 54 | * Zone JS is required by Angular itself. 55 | */ 56 | import 'zone.js/dist/zone'; // Included with Angular CLI. 57 | 58 | 59 | 60 | /*************************************************************************************************** 61 | * APPLICATION IMPORTS 62 | */ 63 | 64 | /** 65 | * Date, currency, decimal and percent pipes. 66 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 67 | */ 68 | // import 'intl'; // Run `npm install --save intl`. 69 | /** 70 | * Need to import at least one locale-data with intl. 71 | */ 72 | // import 'intl/locale-data/jsonp/en'; 73 | -------------------------------------------------------------------------------- /src/app/services/theme.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable() 4 | export class ThemeService { 5 | 6 | themes: Array = [ 7 | { value: 'default', name: 'Default', cssClass: null }, 8 | { value: 'light', name: 'Light', cssClass: 'light-theme' }, 9 | { value: 'snow-white', name: 'Snow white', cssClass: 'snow-white-theme' }, 10 | { value: 'mixed', name: 'Mixed', cssClass: 'mixed-theme' }, 11 | { value: 'Dark', name: 'Dark', cssClass: 'dark-theme' }, 12 | { value: 'black', name: 'Black', cssClass: 'black-theme' } 13 | ]; 14 | 15 | /** 16 | * Loads saved theme and sets required classes to body element. 17 | */ 18 | loadSavedTheme(){ 19 | let theme = localStorage.getItem('theme'); 20 | if(theme !== undefined){ 21 | let selectedTheme = JSON.parse(theme); 22 | if(selectedTheme != null && selectedTheme.cssClass){ 23 | let body = document.getElementsByTagName('body')[0]; 24 | body.classList.add(selectedTheme.cssClass); 25 | } 26 | } 27 | 28 | // Set toolbar width 29 | let fullWidthSaved = localStorage.getItem('fullWidth'); 30 | if(fullWidthSaved){ 31 | this.setFullWidth(JSON.parse(fullWidthSaved)); 32 | } 33 | } 34 | 35 | /** 36 | * Gets current theme. 37 | */ 38 | currentTheme(){ 39 | let storedTheme = localStorage.getItem('theme'); 40 | 41 | if(storedTheme != null){ 42 | let tempTheme = JSON.parse(storedTheme); 43 | let theme = this.themes.filter(theme => theme.value && theme.value === tempTheme.value); 44 | 45 | if(theme != null) 46 | return theme[0]; 47 | } 48 | 49 | return this.themes[0]; 50 | } 51 | 52 | /** 53 | * Sets theme. 54 | * 55 | * @param theme Theme to use. 56 | */ 57 | setTheme(theme: any){ 58 | let body = document.getElementsByTagName('body')[0]; 59 | this.themes.forEach(theme => body.classList.remove(theme.cssClass)); 60 | localStorage.removeItem('theme'); 61 | 62 | if(theme.cssClass){ 63 | localStorage.setItem('theme', JSON.stringify(theme)); 64 | body.classList.add(theme.cssClass); 65 | } 66 | } 67 | 68 | isFullWidth(): boolean{ 69 | let fullWidthSaved = localStorage.getItem('fullWidth'); 70 | if(fullWidthSaved){ 71 | return JSON.parse(fullWidthSaved) as boolean; 72 | } 73 | else{ 74 | let body = document.getElementsByTagName('body')[0]; 75 | return body.classList.contains('full-width'); 76 | } 77 | } 78 | 79 | /** 80 | * Sets toolbar full width options. 81 | * 82 | * @param fullWidth Indicates whether toolbar is displayed in full width. 83 | */ 84 | setFullWidth(fullWidth: boolean){ 85 | let body = document.getElementsByTagName('body')[0]; 86 | localStorage.setItem('fullWidth', JSON.stringify(fullWidth)); 87 | 88 | if(fullWidth){ 89 | body.classList.add('full-width'); 90 | } 91 | else{ 92 | body.classList.remove('full-width'); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/app/layouts/main-layout/main-layout.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, OnDestroy, ViewChild, ElementRef, HostListener } from '@angular/core'; 2 | import { Router, NavigationStart } from '@angular/router'; 3 | import { MatSidenav } from '@angular/material'; 4 | import { ISubscription } from 'rxjs/Subscription' 5 | import 'rxjs/add/operator/filter'; 6 | 7 | @Component({ 8 | selector: 'app-main-layout', 9 | templateUrl: './main-layout.component.html' 10 | }) 11 | export class MainLayoutComponent implements OnInit, OnDestroy { 12 | @ViewChild('sidenav') sidenav: MatSidenav; 13 | 14 | sidenavMode: string; 15 | isSidenavOpen: boolean = true; 16 | navigationSubscription: ISubscription; 17 | 18 | constructor(private router: Router) { } 19 | 20 | /** 21 | * Gets current side nav mode for page refresh, if any. 22 | * Sidenav mode is stored in localStorage for later use. 23 | */ 24 | private wasSidenavOpen(): boolean { 25 | let savedState = localStorage.getItem("sidenavOpen"); 26 | 27 | if (savedState) { 28 | return JSON.parse(savedState); 29 | } 30 | 31 | return true; 32 | } 33 | 34 | /** 35 | * Sets correct sidenav mode based on window size. 36 | */ 37 | private setSidenavMode() { 38 | if (window.innerWidth < 768) { 39 | this.sidenavMode = 'over'; 40 | this.isSidenavOpen = false; 41 | 42 | this.sidenav.close(); 43 | } 44 | else { 45 | this.sidenavMode = 'side'; 46 | this.isSidenavOpen = this.wasSidenavOpen(); 47 | if (this.isSidenavOpen) 48 | this.sidenav.open(); 49 | } 50 | } 51 | 52 | /** 53 | * Creates subscription to navigation change event. 54 | * Used to toggle side menu if one is in "over" mode. 55 | */ 56 | private subscribeToRouteChangeEvent() { 57 | // Hide sidenav on route change if using 'over' mode 58 | this.navigationSubscription = this.router.events 59 | .filter(event => event instanceof NavigationStart) 60 | .subscribe((event: NavigationStart) => { 61 | if (this.sidenav.mode === 'over') 62 | this.sidenav.close(); 63 | }); 64 | } 65 | 66 | /** 67 | * Handes window resilze. 68 | * 69 | * @param event Event args. 70 | */ 71 | @HostListener('window:resize', ['$event']) 72 | onResize(event) { 73 | this.setSidenavMode(); 74 | } 75 | 76 | /** 77 | * Method executed on component initialization. 78 | */ 79 | ngOnInit() { 80 | this.subscribeToRouteChangeEvent(); 81 | this.setSidenavMode(); 82 | } 83 | 84 | /** 85 | * Method executed on component destroy. 86 | */ 87 | ngOnDestroy(): void { 88 | if (this.navigationSubscription) { 89 | this.navigationSubscription.unsubscribe(); 90 | } 91 | } 92 | 93 | /** 94 | * Toggles sidenav based on current sidenav settings. 95 | */ 96 | toggleSidenav() { 97 | if (this.sidenavMode === 'side') { 98 | this.sidenav.toggle(); 99 | this.isSidenavOpen = !this.isSidenavOpen; 100 | 101 | // Keep open state for desktops only 102 | localStorage.setItem("sidenavOpen", JSON.stringify(this.isSidenavOpen)); 103 | } 104 | else { 105 | this.sidenav.open(); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/sass/components/_alerts.scss: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // Alerts 3 | ////////////////////////////////////////////////////////////////////////////// 4 | .alert{ 5 | padding: 15px 10px; 6 | border-width: 1px; 7 | border-style: solid; 8 | font-size: 16px; 9 | border-radius: 2px; 10 | 11 | margin-bottom: 10px; 12 | clear: both; 13 | 14 | box-shadow: 0 3px 1px -2px rgba(0,0,0,.2), 0 2px 2px 0 rgba(0,0,0,.14), 0 1px 5px 0 rgba(0,0,0,.12); 15 | 16 | .mat-icon{ 17 | float: left; 18 | margin-right: 10px; 19 | margin-top: -2px; 20 | } 21 | 22 | &.alert-danger{ 23 | background-color: #D32F2F; 24 | border-color: #D32F2F; 25 | color: #ffffff; 26 | 27 | .mat-icon{ 28 | &::after{ 29 | content: 'error_outline'; 30 | } 31 | } 32 | } 33 | 34 | &.alert-warning{ 35 | background-color: #f6c342; 36 | border-color: #f6c342; 37 | color: #E65100; 38 | 39 | .mat-icon{ 40 | &::after{ 41 | content: 'warning'; 42 | } 43 | } 44 | } 45 | 46 | &.alert-info{ 47 | background-color: #03A9F4; 48 | border-color: #03A9F4; 49 | color: #ffffff; 50 | 51 | .mat-icon{ 52 | &::after{ 53 | content: 'info'; 54 | } 55 | } 56 | } 57 | 58 | &.alert-success{ 59 | background-color: #4CAF50; 60 | border-color: #4CAF50; 61 | color: #ffffff; 62 | 63 | .mat-icon{ 64 | &::after{ 65 | content: 'done'; 66 | } 67 | } 68 | } 69 | } 70 | 71 | 72 | .callout { 73 | border-top: 1px solid #3572b0; 74 | border-right: 1px solid #3572b0; 75 | border-bottom: 1px solid #3572b0; 76 | border-left: 1px solid #3572b0; 77 | border-radius: 3px; 78 | color: currentColor; 79 | line-height: 20px; 80 | margin: 20px 0 20px 0; 81 | overflow-wrap: break-word; 82 | padding-bottom: 20px; 83 | padding-left: 60px; 84 | padding-right: 40px; 85 | padding-top: 20px; 86 | position: relative; 87 | word-wrap: break-word; 88 | word-break: break-word; 89 | 90 | h4{ 91 | margin: 0 0 10px; 92 | font-size: 18px; 93 | font-weight: normal; 94 | } 95 | 96 | &:before { 97 | background-color: #3572b0; 98 | bottom: 0; 99 | left: 0; 100 | position: absolute; 101 | top: 0; 102 | width: 40px; 103 | line-height: 24px; 104 | width: 32px; 105 | padding-left: 8px; 106 | display: flex; 107 | align-items: center; 108 | 109 | direction: ltr; 110 | font-family: 'Material Icons'; 111 | font-size: 24px; 112 | font-style: normal; 113 | font-weight: normal; 114 | letter-spacing: normal; 115 | line-height: 1; 116 | text-transform: none; 117 | white-space: nowrap; 118 | word-wrap: normal; 119 | -webkit-font-feature-settings: 'liga'; 120 | -webkit-font-smoothing: antialiased; 121 | content: 'info'; 122 | color: #ffffff; 123 | } 124 | 125 | &.callout-danger { 126 | border-color: #d04437; 127 | 128 | &:before { 129 | content: 'error_outline'; 130 | background-color: #d04437; 131 | } 132 | } 133 | 134 | &.callout-warning { 135 | border-color: #f6c342; 136 | 137 | &:before { 138 | content: 'warning'; 139 | background-color: #f6c342; 140 | } 141 | } 142 | 143 | &.callout-success { 144 | border-color: #4CAF50; 145 | 146 | &:before { 147 | content: 'done_all'; 148 | background-color: #4CAF50; 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "arrow-return-shorthand": true, 7 | "callable-types": true, 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "eofline": true, 15 | "forin": true, 16 | "import-blacklist": [ 17 | true, 18 | "rxjs" 19 | ], 20 | "import-spacing": true, 21 | "indent": [ 22 | true, 23 | "spaces" 24 | ], 25 | "interface-over-type-literal": true, 26 | "label-position": true, 27 | "max-line-length": [ 28 | true, 29 | 140 30 | ], 31 | "member-access": false, 32 | "member-ordering": [ 33 | true, 34 | { 35 | "order": [ 36 | "static-field", 37 | "instance-field", 38 | "static-method", 39 | "instance-method" 40 | ] 41 | } 42 | ], 43 | "no-arg": true, 44 | "no-bitwise": true, 45 | "no-console": [ 46 | true, 47 | "debug", 48 | "info", 49 | "time", 50 | "timeEnd", 51 | "trace" 52 | ], 53 | "no-construct": true, 54 | "no-debugger": true, 55 | "no-duplicate-super": true, 56 | "no-empty": false, 57 | "no-empty-interface": true, 58 | "no-eval": true, 59 | "no-inferrable-types": [ 60 | true, 61 | "ignore-params" 62 | ], 63 | "no-misused-new": true, 64 | "no-non-null-assertion": true, 65 | "no-shadowed-variable": true, 66 | "no-string-literal": false, 67 | "no-string-throw": true, 68 | "no-switch-case-fall-through": true, 69 | "no-trailing-whitespace": true, 70 | "no-unnecessary-initializer": true, 71 | "no-unused-expression": true, 72 | "no-use-before-declare": true, 73 | "no-var-keyword": true, 74 | "object-literal-sort-keys": false, 75 | "one-line": [ 76 | true, 77 | "check-open-brace", 78 | "check-catch", 79 | "check-else", 80 | "check-whitespace" 81 | ], 82 | "prefer-const": true, 83 | "quotemark": [ 84 | true, 85 | "single" 86 | ], 87 | "radix": true, 88 | "semicolon": [ 89 | true, 90 | "always" 91 | ], 92 | "triple-equals": [ 93 | true, 94 | "allow-null-check" 95 | ], 96 | "typedef-whitespace": [ 97 | true, 98 | { 99 | "call-signature": "nospace", 100 | "index-signature": "nospace", 101 | "parameter": "nospace", 102 | "property-declaration": "nospace", 103 | "variable-declaration": "nospace" 104 | } 105 | ], 106 | "typeof-compare": true, 107 | "unified-signatures": true, 108 | "variable-name": false, 109 | "whitespace": [ 110 | true, 111 | "check-branch", 112 | "check-decl", 113 | "check-operator", 114 | "check-separator", 115 | "check-type" 116 | ], 117 | "directive-selector": [ 118 | true, 119 | "attribute", 120 | "app", 121 | "camelCase" 122 | ], 123 | "component-selector": [ 124 | true, 125 | "element", 126 | "app", 127 | "kebab-case" 128 | ], 129 | "use-input-property-decorator": true, 130 | "use-output-property-decorator": true, 131 | "use-host-property-decorator": true, 132 | "no-input-rename": true, 133 | "no-output-rename": true, 134 | "use-life-cycle-interface": true, 135 | "use-pipe-transform-interface": true, 136 | "component-class-suffix": true, 137 | "directive-class-suffix": true, 138 | "invoke-injectable": true 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/sass/utils/_flex.scss: -------------------------------------------------------------------------------- 1 | // Flexbox display 2 | @mixin flexbox() { 3 | display: -webkit-box; 4 | display: -moz-box; 5 | display: -ms-flexbox; 6 | display: -webkit-flex; 7 | display: flex; 8 | } 9 | 10 | // The 'flex' shorthand 11 | // - applies to: flex items 12 | // , initial, auto, or none 13 | @mixin flex($values) { 14 | -webkit-box-flex: $values; 15 | -moz-box-flex: $values; 16 | -webkit-flex: $values; 17 | -ms-flex: $values; 18 | flex: $values; 19 | } 20 | 21 | // Flex Flow Direction 22 | // - applies to: flex containers 23 | // row | row-reverse | column | column-reverse 24 | @mixin flex-direction($direction) { 25 | -webkit-flex-direction: $direction; 26 | -moz-flex-direction: $direction; 27 | -ms-flex-direction: $direction; 28 | flex-direction: $direction; 29 | } 30 | 31 | // Flex Line Wrapping 32 | // - applies to: flex containers 33 | // nowrap | wrap | wrap-reverse 34 | @mixin flex-wrap($wrap) { 35 | -webkit-flex-wrap: $wrap; 36 | -moz-flex-wrap: $wrap; 37 | -ms-flex-wrap: $wrap; 38 | flex-wrap: $wrap; 39 | } 40 | 41 | // Flex Direction and Wrap 42 | // - applies to: flex containers 43 | // || 44 | @mixin flex-flow($flow) { 45 | -webkit-flex-flow: $flow; 46 | -moz-flex-flow: $flow; 47 | -ms-flex-flow: $flow; 48 | flex-flow: $flow; 49 | } 50 | 51 | // Display Order 52 | // - applies to: flex items 53 | // 54 | @mixin order($val) { 55 | -webkit-box-ordinal-group: $val; 56 | -moz-box-ordinal-group: $val; 57 | -ms-flex-order: $val; 58 | -webkit-order: $val; 59 | order: $val; 60 | } 61 | 62 | // Flex grow factor 63 | // - applies to: flex items 64 | // 65 | @mixin flex-grow($grow) { 66 | -webkit-flex-grow: $grow; 67 | -moz-flex-grow: $grow; 68 | -ms-flex-grow: $grow; 69 | flex-grow: $grow; 70 | } 71 | 72 | // Flex shrink 73 | // - applies to: flex item shrink factor 74 | // 75 | @mixin flex-shrink($shrink) { 76 | -webkit-flex-shrink: $shrink; 77 | -moz-flex-shrink: $shrink; 78 | -ms-flex-shrink: $shrink; 79 | flex-shrink: $shrink; 80 | } 81 | 82 | // Flex basis 83 | // - the initial main size of the flex item 84 | // - applies to: flex itemsnitial main size of the flex item 85 | // 86 | @mixin flex-basis($width) { 87 | -webkit-flex-basis: $width; 88 | -moz-flex-basis: $width; 89 | -ms-flex-basis: $width; 90 | flex-basis: $width; 91 | } 92 | 93 | // Axis Alignment 94 | // - applies to: flex containers 95 | // flex-start | flex-end | center | space-between | space-around 96 | @mixin justify-content($justify) { 97 | -webkit-justify-content: $justify; 98 | -moz-justify-content: $justify; 99 | -ms-justify-content: $justify; 100 | justify-content: $justify; 101 | -ms-flex-pack: $justify; 102 | } 103 | 104 | // Packing Flex Lines 105 | // - applies to: multi-line flex containers 106 | // flex-start | flex-end | center | space-between | space-around | stretch 107 | @mixin align-content($align) { 108 | -webkit-align-content: $align; 109 | -moz-align-content: $align; 110 | -ms-align-content: $align; 111 | align-content: $align; 112 | } 113 | 114 | // Cross-axis Alignment 115 | // - applies to: flex containers 116 | // flex-start | flex-end | center | baseline | stretch 117 | @mixin align-items($align) { 118 | -webkit-align-items: $align; 119 | -moz-align-items: $align; 120 | -ms-align-items: $align; 121 | align-items: $align; 122 | } 123 | 124 | // Cross-axis Alignment 125 | // - applies to: flex items 126 | // auto | flex-start | flex-end | center | baseline | stretch 127 | @mixin align-self($align) { 128 | -webkit-align-self: $align; 129 | -moz-align-self: $align; 130 | -ms-align-self: $align; 131 | align-self: $align; 132 | } 133 | -------------------------------------------------------------------------------- /src/sass/partials/_home.scss: -------------------------------------------------------------------------------- 1 | @import '../base/_variables.scss'; 2 | @import '../utils/_flex'; 3 | 4 | $info-box-height: 90px; 5 | $widget-action-button-size: 22px; 6 | 7 | .home{ 8 | 9 | .mat-card{ 10 | 11 | .mat-card-title{ 12 | .widget-header{ 13 | @include flexbox(); 14 | align-items: center; 15 | } 16 | } 17 | } 18 | 19 | .info-card{ 20 | 21 | background-color: #607d8b !important; 22 | color: #ffffff; 23 | padding: 0; 24 | 25 | &.info-card-link{ 26 | cursor: pointer; 27 | } 28 | 29 | .info-card-icon{ 30 | color: #607d8b; 31 | background-color: #455a64; 32 | border-radius: 2px 0 0 2px; 33 | 34 | display: block; 35 | float: left; 36 | height: $info-box-height; 37 | width: $info-box-height; 38 | text-align: center; 39 | line-height: $info-box-height; 40 | 41 | .mat-icon{ 42 | height: $info-box-height; 43 | width: $info-box-height; 44 | font-size: 48px; 45 | line-height: $info-box-height; 46 | } 47 | } 48 | 49 | .info-card-content{ 50 | padding: 12px 10px 10px; 51 | margin-left: 90px; 52 | color: currentColor!important; 53 | text-transform: uppercase; 54 | font-weight: 400; 55 | 56 | overflow: hidden; 57 | white-space: nowrap; 58 | text-overflow: ellipsis; 59 | 60 | h3 { 61 | font-family: $heading-font-family; 62 | font-weight: 300; 63 | font-size: 32px; 64 | margin: 0 0 12px 0; 65 | } 66 | } 67 | 68 | &.info-card-green{ 69 | background-color: #4caf50 !important; 70 | 71 | .info-card-icon{ 72 | color: #4caf50; 73 | background-color: #43A047; 74 | } 75 | } 76 | 77 | &.info-card-red{ 78 | background-color: #e53935 !important; 79 | 80 | .info-card-icon{ 81 | color: #E53935; 82 | background-color: #d32f2f; 83 | } 84 | } 85 | 86 | &.info-card-blue{ 87 | background-color: #039be5 !important; 88 | 89 | .info-card-icon{ 90 | color: #29B6F6; 91 | background-color: #0288d1; 92 | } 93 | } 94 | } 95 | 96 | .chart{ 97 | padding: 16px; 98 | 99 | .mat-card-title { 100 | font-size: 18px; 101 | } 102 | } 103 | 104 | canvas { 105 | width: 100% !important; 106 | } 107 | 108 | .first-chart{ 109 | canvas { 110 | min-height: 150px; 111 | max-height: 150px; 112 | } 113 | } 114 | 115 | .horizontal-bar{ 116 | canvas { 117 | min-height: 400px; 118 | max-height: 400px; 119 | } 120 | } 121 | 122 | .pie-charts{ 123 | canvas { 124 | min-height: 160px; 125 | max-height: 160px; 126 | } 127 | } 128 | 129 | .progress-metrics{ 130 | h3{ 131 | font-weight: 400; 132 | font-size: 18px; 133 | } 134 | 135 | .progress-wrapper { 136 | position: relative; 137 | margin: 20px auto; 138 | font-size: 24px; 139 | max-width: 160px; 140 | 141 | .progress-label { 142 | font-family: $heading-font-family; 143 | position: absolute; 144 | top: 50%; 145 | left: 50%; 146 | transform: translate(-50%,-50%); 147 | -webkit-transform: translate(-50%,-50%); 148 | -moz-transform: translate(-50%,-50%); 149 | color: currentColor; 150 | opacity: 0.3; 151 | font-size: 32px; 152 | } 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/app/components/users/list/user-list.component.html: -------------------------------------------------------------------------------- 1 |
2 | 5 | 8 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | search 18 | 19 |
20 | Advanced search 21 |
22 |
23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
36 | 37 | 38 | None 39 | {{state}} 40 | 41 | 42 |
43 |
44 | 45 | 46 |
47 |
48 |
49 | 50 |
51 | 52 |
53 | 54 | Search: {{email}} 55 | cancel 56 | 57 | Start date: {{startDate | date: 'dd/MM/yyyy'}} 58 | cancel 59 | 60 | End date: {{endDate | date: 'dd/MM/yyyy'}} 61 | cancel 62 | 63 | State: {{state}} 64 | cancel 65 | 66 | 67 |
68 | 69 | 70 | 71 | 72 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 86 | 87 | 90 | 91 | 92 | 93 | 94 |
73 | 74 | IDNameUsernameEmail
84 | 85 | {{user.id}} 88 | {{user.name}} 89 | {{user.username}}{{user.email}}
95 |
96 |
97 |
98 | 99 | 102 |
-------------------------------------------------------------------------------- /src/sass/base/_layout.scss: -------------------------------------------------------------------------------- 1 | @import '../utils/flex'; 2 | @import '_variables'; 3 | 4 | body{ 5 | @media(min-width: 768px){ 6 | &.full-width{ 7 | .mat-sidenav-container{ 8 | .mat-toolbar{ 9 | min-width: 100%; 10 | max-width: 100%!important; 11 | 12 | // Set logo content and size on full width toobar 13 | .logo{ 14 | margin-left: 10px; 15 | margin-right: 10px; 16 | margin-top: 2px; 17 | width: 125px; 18 | height: 24px; 19 | 20 | background-image: url('/assets/logos.png'); 21 | background-repeat: no-repeat; 22 | background-position-y: -50px; 23 | } 24 | } 25 | 26 | .mat-sidenav{ 27 | margin-top: 64px; 28 | z-index: 0; 29 | 30 | .logo{ 31 | // Hide sidenav logo on full width toolbar 32 | display: none; 33 | } 34 | } 35 | } 36 | } 37 | } 38 | } 39 | 40 | .mat-sidenav-container { 41 | 42 | .mat-card-title{ 43 | font-family: $heading-font-family; 44 | font-weight: 300; 45 | } 46 | 47 | @media(min-width: 768px) { 48 | 49 | .mat-toolbar { 50 | // Use the same transition sidenav is using, so it animates smoothly 51 | transition-property: max-width; 52 | transition-duration: .4s; 53 | transition-timing-function: cubic-bezier(.25,.8,.25,1); 54 | // Set width based on sidenav width 55 | max-width: calc(100% - #{$sidenav-width}); 56 | } 57 | 58 | &.sidenav-closed { 59 | .mat-toolbar { 60 | max-width: 100%; 61 | } 62 | } 63 | } 64 | 65 | .mat-toolbar { 66 | position: fixed; 67 | top: 0; 68 | right: 0; 69 | z-index: 10; 70 | 71 | text-rendering: optimizeLegibility; 72 | -webkit-font-smoothing: antialiased; 73 | 74 | .app-title{ 75 | margin-left: 10px; 76 | font-size: 20px; 77 | font-weight: 400; 78 | } 79 | } 80 | 81 | main { 82 | padding: 80px 16px 16px; 83 | 84 | .mat-tab-body{ 85 | margin-top: 10px; 86 | } 87 | } 88 | } 89 | 90 | // Force dark backdrop for all themes 91 | .mat-drawer-backdrop{ 92 | &.mat-drawer-shown { 93 | background-color: rgba(0, 0, 0, 0.6)!important; 94 | } 95 | } 96 | 97 | .flex-container{ 98 | 99 | @include flexbox(); 100 | align-items: stretch; 101 | 102 | @media(min-width: 768px){ 103 | flex-direction: row; 104 | 105 | .col { 106 | @include flex(1); 107 | margin: 0 0 0 1em; 108 | 109 | &:first-child{ 110 | margin: 0; 111 | } 112 | 113 | &.col-x2{ 114 | @include flex-grow(2); 115 | } 116 | 117 | &.col-x3{ 118 | @include flex-grow(3); 119 | } 120 | 121 | &.col-x4{ 122 | @include flex-grow(4); 123 | } 124 | } 125 | } 126 | 127 | @media(max-width: 767px){ 128 | flex-direction: column; 129 | 130 | .col { 131 | flex: 1; 132 | margin: 1em 0 0 0; 133 | 134 | &:first-child{ 135 | margin: 0; 136 | } 137 | } 138 | } 139 | } 140 | 141 | ////////////////////////////////////////////////////////////////////////////// 142 | // Layout classes 143 | ////////////////////////////////////////////////////////////////////////////// 144 | 145 | section { 146 | margin-bottom: 20px; 147 | } 148 | 149 | [fill], .fill { 150 | flex: 1 1 auto; 151 | } 152 | 153 | [flex] { 154 | -ms-flex: 1; 155 | flex: 1; 156 | box-sizing: border-box; 157 | } 158 | 159 | [layout=column], [layout=row], [layout] { 160 | box-sizing: border-box; 161 | display: -ms-flexbox; 162 | display: flex; 163 | } 164 | 165 | [layout=row] { 166 | -ms-flex-direction: row; 167 | flex-direction: row; 168 | } 169 | 170 | .text-center { 171 | text-align: center !important; 172 | } 173 | 174 | [center], .center{ 175 | margin: 0 auto; 176 | } 177 | 178 | .fixed-bottom-right { 179 | position: fixed !important; 180 | @media(min-width:768px){ 181 | bottom: 24px; 182 | right: 32px; 183 | } 184 | @media(max-width:767px){ 185 | bottom: 20px; 186 | right: 30px; 187 | } 188 | } 189 | 190 | form{ 191 | &.full-width{ 192 | width: 100%; 193 | .mat-form-field{ 194 | &.full-width{ 195 | width: 100%; 196 | } 197 | } 198 | } 199 | } 200 | 201 | .float-right{ 202 | float: right; 203 | &::after{ 204 | clear: both; 205 | } 206 | } 207 | 208 | .clearfix{ 209 | clear: both; 210 | } 211 | 212 | .hide-md{ 213 | @media(max-width: 767px){ 214 | display: none!important; 215 | } 216 | } 217 | 218 | .hide-lg{ 219 | @media(min-width: 768px){ 220 | display: none!important; 221 | } 222 | } -------------------------------------------------------------------------------- /src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule, Title } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { RouterModule, Routes } from '@angular/router'; 4 | import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; 5 | import { FormsModule } from '@angular/forms'; 6 | 7 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 8 | 9 | import { 10 | MatButtonModule, 11 | MatButtonToggleModule, 12 | MatTooltipModule, 13 | MatCheckboxModule, 14 | MatToolbarModule, 15 | MatMenuModule, 16 | MatSidenavModule, 17 | MatFormFieldModule, 18 | MatInputModule, 19 | MatIconModule, 20 | MatSlideToggleModule, 21 | MatDatepickerModule, 22 | MatNativeDateModule, 23 | MatSelectModule, 24 | MatRadioModule, 25 | MatGridListModule, 26 | MatProgressBarModule, 27 | MatListModule, 28 | MatCardModule, 29 | MatDialogModule, 30 | MatTabsModule, 31 | MatChipsModule, 32 | MatSnackBarModule } from '@angular/material'; 33 | 34 | import { ChartsModule } from 'ng2-charts'; 35 | import { RoundProgressModule } from 'angular-svg-round-progressbar'; 36 | import { NgProgressModule, NgProgressInterceptor } from 'ngx-progressbar'; 37 | 38 | import { HttpService } from './services'; 39 | 40 | import { NgInitDirective } from './directives/ng-init.directive'; 41 | 42 | import { NavBarComponent } from './components/shared/navbar/navbar.component'; 43 | import { ToolbarComponent } from './components/shared/toolbar/toolbar.component'; 44 | import { AppComponent } from './components/app/app.component'; 45 | 46 | import { HomeComponent } from './components/home/home.component'; 47 | import { MainLayoutComponent } from './layouts/main-layout/main-layout.component'; 48 | import { LoginLayoutComponent } from './layouts/login-layout/login-layout.component'; 49 | import { LoginComponent } from './components/login/login.component'; 50 | import { UserListComponent } from './components/users/list/user-list.component'; 51 | import { UserDetailsComponent } from './components/users/details/user-details.component'; 52 | import { CreateEditUserComponent } from './components/users/shared/create-edit-user/create-edit-user.component'; 53 | import { SettingsComponent } from './components/settings/settings.component'; 54 | import { ProfileComponent } from './components/profile/profile.component'; 55 | import { LayoutComponent } from './components/layout/base/layout.component'; 56 | import { AlertsLayoutComponent } from './components/layout/alerts-layout/alerts-layout.component'; 57 | import { ButtonsLayoutComponent } from './components/layout/buttons-layout/buttons-layout.component'; 58 | import { TypographyComponent } from './components/layout/typography/typography.component'; 59 | import { ConfirmDialogComponent } from './components/dialogs/confirm-dialog/confirm-dialog.component'; 60 | 61 | const appRoutes: Routes = [ 62 | { 63 | path: '', 64 | component: MainLayoutComponent, 65 | // canActivate: [AuthGuard], 66 | children: [ 67 | { path: '', pathMatch: 'full', redirectTo: '/home' }, 68 | { path: 'home', component: HomeComponent, data: {title: 'Dashboard'} }, 69 | { path: 'users', component: UserListComponent, data: {title: 'Users'}}, 70 | { path: 'users/new', component: CreateEditUserComponent, data: {title: 'New user'} }, 71 | { path: 'users/edit/:id', component: CreateEditUserComponent, data: {title: 'Edit user'} }, 72 | { path: 'users/details/:id', component: UserDetailsComponent, data: {title: 'User details'} }, 73 | { path: 'settings', component: SettingsComponent, data: {title: 'Settings'} }, 74 | { path: 'profile', component: ProfileComponent, data: {title: 'Profile'} }, 75 | { 76 | path: 'layout', data: {title: 'Layout'}, 77 | children:[ 78 | { path: 'base', component: LayoutComponent, data: {title: 'Base layout'} }, 79 | { path: 'alerts', component: AlertsLayoutComponent, data: {title: 'Alerts & Callouts'} }, 80 | { path: 'buttons', component: ButtonsLayoutComponent, data: {title: 'Buttons'} }, 81 | { path: 'typography', component: TypographyComponent, data: {title: 'Typography'} } 82 | ] 83 | } 84 | ] 85 | }, 86 | { 87 | path: '', 88 | component: LoginLayoutComponent, 89 | children: [ 90 | { 91 | path: 'login', 92 | component: LoginComponent 93 | } 94 | ] 95 | }, 96 | { path: '**', redirectTo: '/home' } 97 | 98 | ]; 99 | 100 | @NgModule({ 101 | declarations: [ 102 | AppComponent, 103 | HomeComponent, 104 | MainLayoutComponent, 105 | NavBarComponent, 106 | LoginLayoutComponent, 107 | LoginComponent, 108 | UserListComponent, 109 | UserListComponent, 110 | ToolbarComponent, 111 | UserDetailsComponent, 112 | SettingsComponent, 113 | ProfileComponent, 114 | NgInitDirective, 115 | LayoutComponent, 116 | CreateEditUserComponent, 117 | AlertsLayoutComponent, 118 | ButtonsLayoutComponent, 119 | TypographyComponent, 120 | ConfirmDialogComponent 121 | ], 122 | imports: [ 123 | RouterModule.forRoot(appRoutes), 124 | BrowserModule, 125 | HttpClientModule, 126 | NgProgressModule, 127 | FormsModule, 128 | BrowserAnimationsModule, 129 | MatButtonModule, 130 | MatButtonToggleModule, 131 | MatTooltipModule, 132 | MatCheckboxModule, 133 | MatToolbarModule, 134 | MatMenuModule, 135 | MatSidenavModule, 136 | MatFormFieldModule, 137 | MatInputModule, 138 | MatIconModule, 139 | MatSlideToggleModule, 140 | MatCardModule, 141 | MatDialogModule, 142 | MatDatepickerModule, 143 | MatNativeDateModule, 144 | MatSelectModule, 145 | MatRadioModule, 146 | MatListModule, 147 | MatGridListModule, 148 | MatSnackBarModule, 149 | MatProgressBarModule, 150 | MatTabsModule, 151 | MatChipsModule, 152 | 153 | ChartsModule, 154 | RoundProgressModule 155 | ], 156 | providers: [ 157 | HttpService, 158 | Title, 159 | { 160 | provide: HTTP_INTERCEPTORS, 161 | useClass: NgProgressInterceptor, 162 | multi: true 163 | } 164 | ], 165 | bootstrap: [AppComponent], 166 | entryComponents: [ConfirmDialogComponent] 167 | }) 168 | export class AppModule { } 169 | -------------------------------------------------------------------------------- /src/app/components/home/home.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 6 |
7 | supervisor_account 8 |
9 |
10 |

2345

11 | Downloads 12 |
13 |
14 | 15 | 16 |
17 | verified_user 18 |
19 |
20 |

456

21 | Verified users 22 |
23 |
24 | 25 | 26 |
27 | done_all 28 |
29 |
30 |

123

31 | Comments 32 |
33 |
34 | 35 | 36 |
37 | person_pin 38 |
39 |
40 |

56

41 | Registered 42 |
43 |
44 |
45 |
46 | 47 |
48 |
49 | 50 | 51 |
52 |
Line Chart Example
53 |
54 | 57 | 60 |
61 |
62 |
63 | 64 | 65 | 66 |
67 | 68 | 69 |
70 |
Bar Chart Example
71 |
72 | 75 | 78 | 79 |
80 |
81 |
82 | 83 | 85 | 86 |
87 |
88 |
89 | 90 |
91 |
92 |
93 |

Metric 1

94 |
95 |
70%
96 | 98 |
99 |
100 |
101 |

Metric 2

102 |
103 |
47%
104 | 106 |
107 |
108 |
109 |

Metric 3

110 |
111 |
31%
112 | 114 |
115 |
116 |
117 |

Metric 4

118 |
119 |
12%
120 | 122 |
123 |
124 |
125 |
126 | 127 |
128 |
129 | 130 | Horizontal Bar Example 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 140 | 141 | 142 |
143 |
144 | 145 |
146 |

Pie Chart Example

147 |
148 |
149 | 150 |
151 |
152 | 153 |
154 |
155 | 156 |
157 |
158 |
159 | 160 |
161 |

Available on Github

162 | 163 | 164 | 166 | 167 | 168 |
169 | 170 |
171 | 172 | 173 | 174 |
175 | 176 | 179 |
--------------------------------------------------------------------------------