From 1526235e2b189c516a53f2bd57d2e88faeb05358 Mon Sep 17 00:00:00 2001 From: Abhay Chawla Date: Sat, 11 Aug 2018 00:44:50 +0530 Subject: [PATCH] refractor: shell (#287) * Refractor components. * Shift theme picker component to shared module. * Shift progress bar service into its own folder. * Add footer to app shell. * Replace mat-icon by font-awesome icons. * Fix sidenav visibility bug for handsets. * Add comments. Closes #286, Fixes #285 --- src/app/app.module.ts | 4 +- src/app/core/core.module.ts | 53 +--- src/app/core/i18n.service.ts | 4 +- src/app/core/index.ts | 1 - .../progress-bar.service.spec.ts | 0 .../progress-bar.service.ts | 0 .../progress.interceptor.ts | 0 .../breadcrumb/breadcrumb.component.scss | 20 +- .../shell/breadcrumb/breadcrumb.component.ts | 55 ++++- .../core/shell/breadcrumb/breadcrumb.model.ts | 3 + .../core/shell/content/content.component.html | 1 + .../core/shell/content/content.component.ts | 4 + src/app/core/shell/shell.component.html | 9 + src/app/core/shell/shell.component.scss | 5 +- src/app/core/shell/shell.component.spec.ts | 14 +- src/app/core/shell/shell.component.ts | 41 +++- .../core/shell/sidenav/sidenav.component.html | 53 ++-- .../core/shell/sidenav/sidenav.component.scss | 227 ++++++++++-------- .../core/shell/sidenav/sidenav.component.ts | 20 ++ .../core/shell/toolbar/toolbar.component.html | 119 +++++---- .../core/shell/toolbar/toolbar.component.scss | 73 +++--- .../core/shell/toolbar/toolbar.component.ts | 72 ++++-- src/app/login/login.component.html | 2 +- src/app/login/login.component.spec.ts | 2 +- src/app/shared/footer/footer.component.scss | 2 +- src/app/shared/icons.module.ts | 36 +++ .../language-selector.component.ts | 2 +- src/app/shared/shared.module.ts | 5 +- .../theme-manager.service.spec.ts | 0 .../theme-picker/theme-manager.service.ts | 21 ++ .../theme-picker/theme-picker.component.html | 4 +- .../theme-picker/theme-picker.component.scss | 7 +- .../theme-picker.component.spec.ts | 0 .../theme-picker/theme-picker.component.ts | 23 +- .../theme-storage.service.spec.ts | 0 .../theme-picker/theme-storage.service.ts | 27 +++ .../theme-picker/theme.model.ts | 3 + src/app/web-app.component.ts | 4 +- src/assets/styles/_helper.scss | 76 +++--- 39 files changed, 613 insertions(+), 379 deletions(-) rename src/app/core/{ => progress-bar}/progress-bar.service.spec.ts (100%) rename src/app/core/{ => progress-bar}/progress-bar.service.ts (100%) rename src/app/core/{ => progress-bar}/progress.interceptor.ts (100%) rename src/app/{core/shell/toolbar => shared}/theme-picker/theme-manager.service.spec.ts (100%) rename src/app/{core/shell/toolbar => shared}/theme-picker/theme-manager.service.ts (65%) rename src/app/{core/shell/toolbar => shared}/theme-picker/theme-picker.component.html (77%) rename src/app/{core/shell/toolbar => shared}/theme-picker/theme-picker.component.scss (92%) rename src/app/{core/shell/toolbar => shared}/theme-picker/theme-picker.component.spec.ts (100%) rename src/app/{core/shell/toolbar => shared}/theme-picker/theme-picker.component.ts (74%) rename src/app/{core/shell/toolbar => shared}/theme-picker/theme-storage.service.spec.ts (100%) rename src/app/{core/shell/toolbar => shared}/theme-picker/theme-storage.service.ts (60%) rename src/app/{core/shell/toolbar => shared}/theme-picker/theme.model.ts (83%) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 3c26db7cd..967752a2c 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -8,12 +8,11 @@ import { ServiceWorkerModule } from '@angular/service-worker'; import { TranslateModule } from '@ngx-translate/core'; import { NgxChartsModule } from '@swimlane/ngx-charts'; -import { environment } from '../environments/environment'; +import { environment } from 'environments/environment'; import { WebAppComponent } from './web-app.component'; import { CoreModule } from './core/core.module'; -import { SharedModule } from './shared/shared.module'; import { NavigationModule } from './navigation/navigation.module'; import { HomeModule } from './home/home.module'; import { AboutModule } from './about/about.module'; @@ -37,7 +36,6 @@ import { SettingsModule } from './settings/settings.module'; TranslateModule.forRoot(), NgxChartsModule, CoreModule, - SharedModule, HomeModule, NavigationModule, AboutModule, diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index 20c9636a8..53c0f70df 100644 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -1,5 +1,4 @@ import { NgModule, Optional, SkipSelf } from '@angular/core'; -import { CommonModule } from '@angular/common'; import { HTTP_INTERCEPTORS, HttpClient, HttpClientModule } from '@angular/common/http'; import { RouteReuseStrategy, RouterModule } from '@angular/router'; @@ -46,70 +45,32 @@ import { TranslateModule } from '@ngx-translate/core'; import { RouteReusableStrategy } from './route-reusable-strategy'; import { AuthenticationService } from './authentication/authentication.service'; import { AuthenticationGuard } from './authentication/authentication.guard'; -import { I18nService } from './i18n.service'; import { HttpService } from './http/http.service'; import { HttpCacheService } from './http/http-cache.service'; -import { ProgressBarService } from './progress-bar.service'; -import { ProgressInterceptor } from './progress.interceptor'; +import { ProgressBarService } from './progress-bar/progress-bar.service'; +import { ProgressInterceptor } from './progress-bar/progress.interceptor'; import { ApiPrefixInterceptor } from './http/api-prefix.interceptor'; import { ErrorHandlerInterceptor } from './http/error-handler.interceptor'; import { CacheInterceptor } from './http/cache.interceptor'; import { ShellComponent } from './shell/shell.component'; import { SidenavComponent } from './shell/sidenav/sidenav.component'; -import { ThemePickerComponent } from './shell/toolbar/theme-picker/theme-picker.component'; import { ToolbarComponent } from './shell/toolbar/toolbar.component'; import { ContentComponent } from './shell/content/content.component'; import { BreadcrumbComponent } from './shell/breadcrumb/breadcrumb.component'; import { AuthenticationInterceptor } from './authentication/authentication.interceptor'; +import { SharedModule } from '../shared'; @NgModule({ imports: [ - CommonModule, + SharedModule, HttpClientModule, TranslateModule, - RouterModule, - LayoutModule, - FlexLayoutModule, - MatCheckboxModule, - MatCheckboxModule, - MatButtonModule, - MatInputModule, - MatAutocompleteModule, - MatDatepickerModule, - MatNativeDateModule, - MatFormFieldModule, - MatRadioModule, - MatSelectModule, - MatSliderModule, - MatSlideToggleModule, - MatMenuModule, - MatSidenavModule, - MatToolbarModule, - MatListModule, - MatGridListModule, - MatCardModule, - MatStepperModule, - MatTabsModule, - MatExpansionModule, - MatButtonToggleModule, - MatChipsModule, - MatIconModule, - MatProgressSpinnerModule, - MatProgressBarModule, - MatDialogModule, - MatTooltipModule, - MatSnackBarModule, - MatTableModule, - MatTreeModule, - MatSortModule, - MatPaginatorModule, - MatDividerModule + RouterModule ], declarations: [ ShellComponent, SidenavComponent, - ThemePickerComponent, ToolbarComponent, ContentComponent, BreadcrumbComponent @@ -150,13 +111,11 @@ import { AuthenticationInterceptor } from './authentication/authentication.inter MatTreeModule, MatSortModule, MatPaginatorModule, - MatDividerModule, - ThemePickerComponent + MatDividerModule ], providers: [ AuthenticationService, AuthenticationGuard, - I18nService, HttpCacheService, ProgressBarService, ProgressInterceptor, diff --git a/src/app/core/i18n.service.ts b/src/app/core/i18n.service.ts index 6ed9ed34d..2d5d03e31 100644 --- a/src/app/core/i18n.service.ts +++ b/src/app/core/i18n.service.ts @@ -20,7 +20,9 @@ export function extract(s: string) { return s; } -@Injectable() +@Injectable({ + providedIn: 'root' +}) export class I18nService { defaultLanguage: string; diff --git a/src/app/core/index.ts b/src/app/core/index.ts index ee68fd0be..38fbfbea9 100644 --- a/src/app/core/index.ts +++ b/src/app/core/index.ts @@ -1,6 +1,5 @@ export * from './core.module'; export * from './authentication/authentication.service'; -// export * from './authentication/authentication.service.mock'; export * from './authentication/authentication.guard'; export * from './i18n.service'; export * from './http/http.service'; diff --git a/src/app/core/progress-bar.service.spec.ts b/src/app/core/progress-bar/progress-bar.service.spec.ts similarity index 100% rename from src/app/core/progress-bar.service.spec.ts rename to src/app/core/progress-bar/progress-bar.service.spec.ts diff --git a/src/app/core/progress-bar.service.ts b/src/app/core/progress-bar/progress-bar.service.ts similarity index 100% rename from src/app/core/progress-bar.service.ts rename to src/app/core/progress-bar/progress-bar.service.ts diff --git a/src/app/core/progress.interceptor.ts b/src/app/core/progress-bar/progress.interceptor.ts similarity index 100% rename from src/app/core/progress.interceptor.ts rename to src/app/core/progress-bar/progress.interceptor.ts diff --git a/src/app/core/shell/breadcrumb/breadcrumb.component.scss b/src/app/core/shell/breadcrumb/breadcrumb.component.scss index a0ea2b443..a9a23f3e4 100644 --- a/src/app/core/shell/breadcrumb/breadcrumb.component.scss +++ b/src/app/core/shell/breadcrumb/breadcrumb.component.scss @@ -14,7 +14,7 @@ font-weight: 400; } - .separator:before { + .separator::before { content: ""; border: 1.5px solid #000; margin: 0 0.6rem; @@ -30,19 +30,17 @@ a { text-decoration: none; color: #0275d8; + + &:hover { + text-decoration: underline; + } } - a:hover { - text-decoration: underline; + + &::after { + content: "/"; + margin: 0 0.4rem; } } - - .breadcrumb-link:after { - content: "/"; - margin: 0 0.4rem; - } - } - } - } diff --git a/src/app/core/shell/breadcrumb/breadcrumb.component.ts b/src/app/core/shell/breadcrumb/breadcrumb.component.ts index 3bbfefe52..445287974 100644 --- a/src/app/core/shell/breadcrumb/breadcrumb.component.ts +++ b/src/app/core/shell/breadcrumb/breadcrumb.component.ts @@ -1,10 +1,45 @@ +/** Angular Imports */ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router, NavigationEnd } from '@angular/router'; +/** rxjs Imports */ import { filter } from 'rxjs/operators'; +/** Custom Model */ import { Breadcrumb } from './breadcrumb.model'; +/** + * Route data property to generate breadcrumb using a static string. + * + * Example- breadcrumb: 'Home' + */ +const routeDataBreadcrumb = 'breadcrumb'; +/** + * Route data property to generate breadcrumb using given route parameter name. + * + * Example- routeParamBreadcrumb: 'id' + */ +const routeParamBreadcrumb = 'routeParamBreadcrumb'; +/** + * Route data property to generate breadcrumb using resolved data property name. + * + * Use array to specify name for a nested object property. + * + * Example- routeResolveBreadcrumb: ['user', 'username'] + */ +const routeResolveBreadcrumb = 'routeResolveBreadcrumb'; +/** + * Route data property to specify whether generated breadcrumb should have a link. + * + * True by default. Specify false if a link is not required. + * + * Example- addBreadcrumbLink: false + */ +const routeAddBreadcrumbLink = 'addBreadcrumbLink'; + +/** + * Generate breadcrumbs dynamically via route configuration. + */ @Component({ selector: 'mifosx-breadcrumb', templateUrl: './breadcrumb.component.html', @@ -12,19 +47,26 @@ import { Breadcrumb } from './breadcrumb.model'; }) export class BreadcrumbComponent implements OnInit { + /** Array of breadcrumbs. */ breadcrumbs: Breadcrumb[]; + /** + * Generates the breadcrumbs. + * @param {ActivatedRoute} activatedRoute Activate Route. + * @param {Router} router Router for navigation. + */ constructor(private activatedRoute: ActivatedRoute, private router: Router) { this.generateBreadcrumbs(); } - generateBreadcrumbs() { - const routeDataBreadcrumb = 'breadcrumb'; - const routeParamBreadcrumb = 'routeParamBreadcrumb'; - const routeResolveBreadcrumb = 'routeResolveBreadcrumb'; - const routeAddBreadcrumbLink = 'addBreadcrumbLink'; + ngOnInit() { + } + /** + * Generates the array of breadcrumbs for the visited route. + */ + generateBreadcrumbs() { const onNavigationEnd = this.router.events.pipe(filter(event => event instanceof NavigationEnd)); onNavigationEnd.subscribe(() => { @@ -86,7 +128,4 @@ export class BreadcrumbComponent implements OnInit { }); } - ngOnInit() { - } - } diff --git a/src/app/core/shell/breadcrumb/breadcrumb.model.ts b/src/app/core/shell/breadcrumb/breadcrumb.model.ts index e88fdb43e..2bbc0a497 100644 --- a/src/app/core/shell/breadcrumb/breadcrumb.model.ts +++ b/src/app/core/shell/breadcrumb/breadcrumb.model.ts @@ -1,3 +1,6 @@ +/** + * Breadcrumb model. + */ export interface Breadcrumb { label: string; url: string; diff --git a/src/app/core/shell/content/content.component.html b/src/app/core/shell/content/content.component.html index 0680b43f9..638208949 100644 --- a/src/app/core/shell/content/content.component.html +++ b/src/app/core/shell/content/content.component.html @@ -1 +1,2 @@ + diff --git a/src/app/core/shell/content/content.component.ts b/src/app/core/shell/content/content.component.ts index 35b20ea38..75dcba1ba 100644 --- a/src/app/core/shell/content/content.component.ts +++ b/src/app/core/shell/content/content.component.ts @@ -1,5 +1,9 @@ +/** Angular Imports */ import { Component, OnInit } from '@angular/core'; +/** + * Content component. + */ @Component({ selector: 'mifosx-content', templateUrl: './content.component.html', diff --git a/src/app/core/shell/shell.component.html b/src/app/core/shell/shell.component.html index 8f2e2c495..c78a2f2ee 100644 --- a/src/app/core/shell/shell.component.html +++ b/src/app/core/shell/shell.component.html @@ -1,5 +1,7 @@ + + + + + + + + + diff --git a/src/app/core/shell/shell.component.scss b/src/app/core/shell/shell.component.scss index 9f38a12a7..cf371c72d 100644 --- a/src/app/core/shell/shell.component.scss +++ b/src/app/core/shell/shell.component.scss @@ -3,10 +3,10 @@ height: 100vh; .sidebar-panel { - background-color: white; // TODO: Theme Configuration + background-color: #fff; min-height: 100vh; overflow: hidden; - 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); + box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12); } .sidebar-full { @@ -16,5 +16,4 @@ .sidebar-compact { width: 4rem; } - } diff --git a/src/app/core/shell/shell.component.spec.ts b/src/app/core/shell/shell.component.spec.ts index ed8093a99..504006a89 100644 --- a/src/app/core/shell/shell.component.spec.ts +++ b/src/app/core/shell/shell.component.spec.ts @@ -1,10 +1,5 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { TranslateModule } from '@ngx-translate/core'; -import { AuthenticationService } from '../authentication/authentication.service'; -import { MockAuthenticationService } from '../authentication/authentication.service.mock'; -import { CoreModule } from '../core.module'; import { ShellComponent } from './shell.component'; describe('ShellComponent', () => { @@ -13,14 +8,7 @@ describe('ShellComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ - RouterTestingModule, - TranslateModule.forRoot(), - CoreModule - ], - providers: [ - { provide: AuthenticationService, useClass: MockAuthenticationService } - ] + declarations: [ ShellComponent ] }) .compileComponents(); })); diff --git a/src/app/core/shell/shell.component.ts b/src/app/core/shell/shell.component.ts index 07b5b4124..84cbaa365 100644 --- a/src/app/core/shell/shell.component.ts +++ b/src/app/core/shell/shell.component.ts @@ -1,10 +1,17 @@ +/** Angular Imports */ import { Component, OnInit, ChangeDetectorRef, OnDestroy } from '@angular/core'; import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; -import { Observable } from 'rxjs'; +/** rxjs Imports */ +import { Observable, Subscription } from 'rxjs'; import { map } from 'rxjs/operators'; -import { ProgressBarService } from '../progress-bar.service'; +/** Custom Services */ +import { ProgressBarService } from '../progress-bar/progress-bar.service'; + +/** + * Shell component. + */ @Component({ selector: 'mifosx-shell', templateUrl: './shell.component.html', @@ -12,30 +19,48 @@ import { ProgressBarService } from '../progress-bar.service'; }) export class ShellComponent implements OnInit, OnDestroy { + /** Subscription to breakpoint observer for handset. */ isHandset$: Observable = this.breakpointObserver.observe(Breakpoints.Handset) - .pipe( - map(result => result.matches) - ); - sidenavCollapsed = false; + .pipe( + map(result => result.matches) + ); + /** Sets the initial state of sidenav as collapsed. Not collapsed if false. */ + sidenavCollapsed = true; + /** Progress bar mode. */ progressBarMode: string; - progressBar$: any; + /** Subscription to progress bar. */ + progressBar$: Subscription; + /** + * @param {BreakpointObserver} breakpointObserver Breakpoint Observer to detect screen size. + * @param {ProgressBarService} progressBarService Progress Bar Service. + * @param {ChangeDetectorRef} cdr Change Detector Ref. + */ constructor(private breakpointObserver: BreakpointObserver, private progressBarService: ProgressBarService, private cdr: ChangeDetectorRef) { } + /** + * Subscribes to progress bar to update its mode. + */ ngOnInit() { - this.sidenavCollapsed = true; this.progressBar$ = this.progressBarService.updateProgressBar.subscribe((mode: string) => { this.progressBarMode = mode; this.cdr.detectChanges(); }); } + /** + * Toggles the current collapsed state of sidenav according to the emitted event. + * @param {boolean} event denotes state of sidenav + */ toggleCollapse($event: boolean) { this.sidenavCollapsed = $event; } + /** + * Unsubscribes from progress bar. + */ ngOnDestroy() { this.progressBar$.unsubscribe(); } diff --git a/src/app/core/shell/sidenav/sidenav.component.html b/src/app/core/shell/sidenav/sidenav.component.html index 215062527..05af9c12d 100644 --- a/src/app/core/shell/sidenav/sidenav.component.html +++ b/src/app/core/shell/sidenav/sidenav.component.html @@ -6,6 +6,7 @@ - + diff --git a/src/app/login/login.component.spec.ts b/src/app/login/login.component.spec.ts index 797757697..d6d85a846 100644 --- a/src/app/login/login.component.spec.ts +++ b/src/app/login/login.component.spec.ts @@ -2,7 +2,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { LoginComponent } from './login.component'; -describe('LanguageSelectorComponent', () => { +describe('LoginComponent', () => { let component: LoginComponent; let fixture: ComponentFixture; diff --git a/src/app/shared/footer/footer.component.scss b/src/app/shared/footer/footer.component.scss index d741ce9e6..e7500dd88 100644 --- a/src/app/shared/footer/footer.component.scss +++ b/src/app/shared/footer/footer.component.scss @@ -1,6 +1,6 @@ #footer { .divider { - margin: 1rem 1rem 0.5rem; + margin: 2.5rem 1rem 0.5rem; width: 4rem; } diff --git a/src/app/shared/icons.module.ts b/src/app/shared/icons.module.ts index 9b013bd63..05149ec74 100644 --- a/src/app/shared/icons.module.ts +++ b/src/app/shared/icons.module.ts @@ -5,25 +5,61 @@ import { NgModule } from '@angular/core'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { library } from '@fortawesome/fontawesome-svg-core'; import { + faBars, + faBell, + faChartBar, faCheckCircle, + faChevronLeft, + faChevronRight, + faCog, faEye, faEyeSlash, faFileUpload, + faFillDrip, + faHome, + faLocationArrow, faLock, + faMoneyBillAlt, + faPlus, faSearch, + faShieldAlt, + faSignOutAlt, + faSitemap, + faSync, + faTachometerAlt, + faUniversity, faUserCircle, + faUsers, faUserShield } from '@fortawesome/free-solid-svg-icons'; /** Add icons to the library for convenient access in other components. */ library.add( + faBars, + faBell, + faChartBar, faCheckCircle, + faChevronLeft, + faChevronRight, + faCog, faEye, faEyeSlash, faFileUpload, + faFillDrip, + faHome, + faLocationArrow, faLock, + faMoneyBillAlt, + faPlus, faSearch, + faShieldAlt, + faSignOutAlt, + faSitemap, + faSync, + faTachometerAlt, + faUniversity, faUserCircle, + faUsers, faUserShield ); diff --git a/src/app/shared/language-selector/language-selector.component.ts b/src/app/shared/language-selector/language-selector.component.ts index 379c73262..eb68d4d50 100644 --- a/src/app/shared/language-selector/language-selector.component.ts +++ b/src/app/shared/language-selector/language-selector.component.ts @@ -3,7 +3,7 @@ import { Component, OnInit } from '@angular/core'; import { FormControl } from '@angular/forms'; /** Custom Services */ -import { I18nService } from 'app/core'; +import { I18nService } from '../../core/i18n.service'; /** * Language selector component. diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index ab2e5fb08..f1a9115ec 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -8,6 +8,7 @@ import { DeleteDialogComponent } from './delete-dialog/delete-dialog.component'; import { FileUploadComponent } from './file-upload/file-upload.component'; import { FooterComponent } from './footer/footer.component'; import { LanguageSelectorComponent } from './language-selector/language-selector.component'; +import { ThemePickerComponent } from './theme-picker/theme-picker.component'; /** Custom Modules */ import { IconsModule } from './icons.module'; @@ -29,12 +30,14 @@ import { MaterialModule } from './material.module'; DeleteDialogComponent, FileUploadComponent, FooterComponent, - LanguageSelectorComponent + LanguageSelectorComponent, + ThemePickerComponent ], exports: [ FileUploadComponent, FooterComponent, LanguageSelectorComponent, + ThemePickerComponent, CommonModule, IconsModule, MaterialModule, diff --git a/src/app/core/shell/toolbar/theme-picker/theme-manager.service.spec.ts b/src/app/shared/theme-picker/theme-manager.service.spec.ts similarity index 100% rename from src/app/core/shell/toolbar/theme-picker/theme-manager.service.spec.ts rename to src/app/shared/theme-picker/theme-manager.service.spec.ts diff --git a/src/app/core/shell/toolbar/theme-picker/theme-manager.service.ts b/src/app/shared/theme-picker/theme-manager.service.ts similarity index 65% rename from src/app/core/shell/toolbar/theme-picker/theme-manager.service.ts rename to src/app/shared/theme-picker/theme-manager.service.ts index cb28501ab..108c0aff7 100644 --- a/src/app/core/shell/toolbar/theme-picker/theme-manager.service.ts +++ b/src/app/shared/theme-picker/theme-manager.service.ts @@ -1,18 +1,30 @@ +/** Angular Imports */ import { Injectable } from '@angular/core'; +/** + * Theme manager service. + */ @Injectable({ providedIn: 'root' }) export class ThemeManagerService { + /** Stylesheet class for the theme of the application. */ private themeManagerClass = 'theme-manager'; constructor() { } + /** + * Sets a new theme for the application. + * @param {string} href Link to stylesheet. + */ setTheme(href: string) { this.getLinkElement().setAttribute('href', href); } + /** + * Removes the current theme of the application. + */ removeTheme() { const existingLinkElement = this.getExistingLinkElement(); if (existingLinkElement) { @@ -20,14 +32,23 @@ export class ThemeManagerService { } } + /** + * @returns link element of stylesheet + */ private getLinkElement() { return this.getExistingLinkElement() || this.createLinkElement(); } + /** + * @returns existing link element of stylesheet with theme manager class + */ private getExistingLinkElement() { return document.head.querySelector(`link[rel="stylesheet"].${this.themeManagerClass}`); } + /** + * @returns newly created link element of stylesheet with theme manager class + */ private createLinkElement() { const linkElement = document.createElement('link'); linkElement.setAttribute('rel', 'stylesheet'); diff --git a/src/app/core/shell/toolbar/theme-picker/theme-picker.component.html b/src/app/shared/theme-picker/theme-picker.component.html similarity index 77% rename from src/app/core/shell/toolbar/theme-picker/theme-picker.component.html rename to src/app/shared/theme-picker/theme-picker.component.html index f3204fa17..91153f19b 100644 --- a/src/app/core/shell/toolbar/theme-picker/theme-picker.component.html +++ b/src/app/shared/theme-picker/theme-picker.component.html @@ -1,5 +1,5 @@ @@ -7,7 +7,7 @@
- check_circle +
diff --git a/src/app/core/shell/toolbar/theme-picker/theme-picker.component.scss b/src/app/shared/theme-picker/theme-picker.component.scss similarity index 92% rename from src/app/core/shell/toolbar/theme-picker/theme-picker.component.scss rename to src/app/shared/theme-picker/theme-picker.component.scss index b2a98433d..2d4ebeeb1 100644 --- a/src/app/core/shell/toolbar/theme-picker/theme-picker.component.scss +++ b/src/app/shared/theme-picker/theme-picker.component.scss @@ -26,19 +26,20 @@ $theme-picker-accent-stripe-size: 6px; .mifosx-theme-chosen-icon { color: white; position: absolute; - left: 50%; top: 50%; + left: 50%; + top: 50%; transform: translate(-50%, -50%); } &::after { - content: ''; + content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; box-sizing: border-box; - border: 1px solid rgba(0,0,0,.2); + border: 1px solid rgba(0, 0, 0, 0.2); border-radius: 50%; } } diff --git a/src/app/core/shell/toolbar/theme-picker/theme-picker.component.spec.ts b/src/app/shared/theme-picker/theme-picker.component.spec.ts similarity index 100% rename from src/app/core/shell/toolbar/theme-picker/theme-picker.component.spec.ts rename to src/app/shared/theme-picker/theme-picker.component.spec.ts diff --git a/src/app/core/shell/toolbar/theme-picker/theme-picker.component.ts b/src/app/shared/theme-picker/theme-picker.component.ts similarity index 74% rename from src/app/core/shell/toolbar/theme-picker/theme-picker.component.ts rename to src/app/shared/theme-picker/theme-picker.component.ts index 5a27abf43..dc86faf9d 100644 --- a/src/app/core/shell/toolbar/theme-picker/theme-picker.component.ts +++ b/src/app/shared/theme-picker/theme-picker.component.ts @@ -1,8 +1,17 @@ +/** Angular Imports */ import { Component, OnInit, ViewEncapsulation } from '@angular/core'; +/** Custom Model */ import { Theme } from './theme.model'; + +/** Custom Services */ import { ThemeStorageService } from './theme-storage.service'; +/** + * Theme picker component. + * + * TODO: Customization of theme for every component and custom background with darker contrast. + */ @Component({ selector: 'mifosx-theme-picker', templateUrl: './theme-picker.component.html', @@ -11,6 +20,7 @@ import { ThemeStorageService } from './theme-storage.service'; }) export class ThemePickerComponent implements OnInit { + /** Default theme for the application. */ currentTheme: Theme = { href: 'denim-yellowgreen.css', primary: '#1074B9', @@ -18,6 +28,7 @@ export class ThemePickerComponent implements OnInit { isDark: false, isDefault: true }; + /** Available themes for the application. */ themes = [ this.currentTheme, { @@ -38,7 +49,7 @@ export class ThemePickerComponent implements OnInit { accent: '#FFC107', isDark: false }, - { // TODO: Remove Dark Themes + { href: 'pink-bluegrey.css', primary: '#E91E63', accent: '#607D8B', @@ -52,8 +63,14 @@ export class ThemePickerComponent implements OnInit { } ]; + /** + * @param {ThemeStorageService} themeStorageService Theme Storage Service. + */ constructor(public themeStorageService: ThemeStorageService) { } + /** + * Initializes the theme for the application. + */ ngOnInit() { const theme = this.themeStorageService.getTheme(); if (theme) { @@ -61,6 +78,10 @@ export class ThemePickerComponent implements OnInit { } } + /** + * Installs a new theme for the application. + * @param {Theme} theme + */ installTheme(theme: Theme) { this.currentTheme = theme; this.themeStorageService.installTheme(theme); diff --git a/src/app/core/shell/toolbar/theme-picker/theme-storage.service.spec.ts b/src/app/shared/theme-picker/theme-storage.service.spec.ts similarity index 100% rename from src/app/core/shell/toolbar/theme-picker/theme-storage.service.spec.ts rename to src/app/shared/theme-picker/theme-storage.service.spec.ts diff --git a/src/app/core/shell/toolbar/theme-picker/theme-storage.service.ts b/src/app/shared/theme-picker/theme-storage.service.ts similarity index 60% rename from src/app/core/shell/toolbar/theme-picker/theme-storage.service.ts rename to src/app/shared/theme-picker/theme-storage.service.ts index 00df4eee9..e0ee1c727 100644 --- a/src/app/core/shell/toolbar/theme-picker/theme-storage.service.ts +++ b/src/app/shared/theme-picker/theme-storage.service.ts @@ -1,33 +1,60 @@ +/** Angular Imports */ import {Injectable, EventEmitter} from '@angular/core'; +/** Custom Model */ import { Theme } from './theme.model'; + +/** Custom Services */ import { ThemeManagerService } from './theme-manager.service'; +/** + * Theme storage service. + */ @Injectable({ providedIn: 'root' }) export class ThemeStorageService { + /** Key to store current theme of application in local storage. */ private themeStorageKey = 'mifosXTheme'; + /** Theme update event. */ onThemeUpdate: EventEmitter; + /** + * Initializes theme update event. + * @param {ThemeManagerService} themeManagerService + */ constructor(public themeManagerService: ThemeManagerService) { this.onThemeUpdate = new EventEmitter(); } + /** + * Stores current theme in local storage and emits a theme update event. + * @param mifosXTheme + */ storeTheme(mifosXTheme: Theme) { localStorage.setItem(this.themeStorageKey, JSON.stringify(mifosXTheme)); this.onThemeUpdate.emit(mifosXTheme); } + /** + * @returns current theme from local storage + */ getTheme(): Theme { return JSON.parse(localStorage.getItem(this.themeStorageKey)); } + /** + * Removes current theme from local storage. + */ clearTheme() { localStorage.removeItem(this.themeStorageKey); } + /** + * Sets a new theme for the application and stores in local storage. + * @param {Theme} theme + */ installTheme(theme: Theme) { if (theme.isDefault) { this.themeManagerService.removeTheme(); diff --git a/src/app/core/shell/toolbar/theme-picker/theme.model.ts b/src/app/shared/theme-picker/theme.model.ts similarity index 83% rename from src/app/core/shell/toolbar/theme-picker/theme.model.ts rename to src/app/shared/theme-picker/theme.model.ts index 453853a70..caebefdc7 100644 --- a/src/app/core/shell/toolbar/theme-picker/theme.model.ts +++ b/src/app/shared/theme-picker/theme.model.ts @@ -1,3 +1,6 @@ +/** + * Theme model. + */ export interface Theme { href: string; primary: string; diff --git a/src/app/web-app.component.ts b/src/app/web-app.component.ts index 26db58795..01f8b6fcb 100644 --- a/src/app/web-app.component.ts +++ b/src/app/web-app.component.ts @@ -7,9 +7,9 @@ import { TranslateService } from '@ngx-translate/core'; import { merge } from 'rxjs'; import { filter, map, mergeMap } from 'rxjs/operators'; -import { environment } from '../environments/environment'; +import { environment } from 'environments/environment'; import { Logger, I18nService } from './core'; -import { ThemeStorageService } from './core/shell/toolbar/theme-picker/theme-storage.service'; +import { ThemeStorageService } from './shared/theme-picker/theme-storage.service'; import { AlertService } from './core/alert.service'; const log = new Logger('MifosX'); diff --git a/src/assets/styles/_helper.scss b/src/assets/styles/_helper.scss index 7305a62d5..2347c54ef 100644 --- a/src/assets/styles/_helper.scss +++ b/src/assets/styles/_helper.scss @@ -3,56 +3,40 @@ @import "width-height"; @import "z-index"; -body, html { - width: 100%; - height: 100%; - position: relative; - overflow: hidden; - -webkit-tap-highlight-color: transparent; - min-height: 100%; - -webkit-font-smoothing: antialiased; - } +body, +html { + width: 100%; + height: 100%; + position: relative; + overflow: hidden; + -webkit-tap-highlight-color: transparent; + min-height: 100%; + -webkit-font-smoothing: antialiased; +} - html { - font-size: 16px; - } +html { + font-size: 16px; +} - body { - margin: 0; - padding: 0; - font-weight: 400; - font-size: .875rem; - color: rgba(0,0,0,.87); - line-height: 1.5; - font-family: Roboto, Helvetica Neue, sans-serif; - } +body { + margin: 0; + padding: 0; + font-weight: 400; + font-size: .875rem; + color: rgba(0,0,0,.87); + line-height: 1.5; + font-family: Roboto, Helvetica Neue, sans-serif; +} - div { - box-sizing: border-box; - } +div { + box-sizing: border-box; +} - .container { - margin: 0 auto; - max-width: 74rem; - width: 90%; - } - - .mat-icon-button.xs-button { - height: 20px; - width: 20px; - line-height: 20px; - } - - .mat-icon-button.xs-button .mat-icon { - font-size: 16px; - line-height: 20px; - height: 20px; - width: 20px; - } - - .text-muted { - color: rgba(0, 0, 0, .54); - } +.container { + margin: 0 auto; + max-width: 74rem; + width: 90%; +} .mb-05 { margin-bottom: .5rem;