├── .browserslistrc ├── .editorconfig ├── .firebaserc ├── .gitignore ├── README.md ├── angular.json ├── firebase.json ├── karma.conf.js ├── package-lock.json ├── package.json ├── src ├── app │ ├── app-dictionary.service.ts │ ├── app-material-importer.module.ts │ ├── app-routing.module.ts │ ├── app-utility.service.ts │ ├── app.component.html │ ├── app.component.scss │ ├── app.component.spec.ts │ ├── app.component.ts │ ├── app.interceptor.ts │ ├── app.module.ts │ ├── app.validators.ts │ ├── global-components │ │ ├── banner │ │ │ ├── banner.component.html │ │ │ ├── banner.component.scss │ │ │ ├── banner.component.spec.ts │ │ │ └── banner.component.ts │ │ ├── dashboard │ │ │ ├── dashboard.component.html │ │ │ ├── dashboard.component.scss │ │ │ ├── dashboard.component.spec.ts │ │ │ └── dashboard.component.ts │ │ ├── footer │ │ │ ├── footer.component.html │ │ │ ├── footer.component.scss │ │ │ ├── footer.component.spec.ts │ │ │ └── footer.component.ts │ │ ├── header │ │ │ ├── header.component.html │ │ │ ├── header.component.scss │ │ │ ├── header.component.spec.ts │ │ │ └── header.component.ts │ │ ├── login │ │ │ ├── login.component.html │ │ │ ├── login.component.scss │ │ │ ├── login.component.spec.ts │ │ │ └── login.component.ts │ │ └── secure-container │ │ │ ├── secure-container.component.html │ │ │ ├── secure-container.component.scss │ │ │ ├── secure-container.component.spec.ts │ │ │ └── secure-container.component.ts │ └── modules │ │ ├── __shared-utilities │ │ ├── drag-and-drop-directive │ │ │ └── drag-and-drop.directive.ts │ │ ├── modhyobitto-dialog │ │ │ ├── modhyobitto-dialog.component.html │ │ │ ├── modhyobitto-dialog.component.scss │ │ │ ├── modhyobitto-dialog.component.spec.ts │ │ │ └── modhyobitto-dialog.component.ts │ │ ├── modhyobitto-file-uploader │ │ │ ├── modhyobitto-file-uploader.component.html │ │ │ ├── modhyobitto-file-uploader.component.scss │ │ │ ├── modhyobitto-file-uploader.component.spec.ts │ │ │ └── modhyobitto-file-uploader.component.ts │ │ ├── modhyobitto-form-field │ │ │ ├── modhyobitto-form-field.component.html │ │ │ ├── modhyobitto-form-field.component.scss │ │ │ ├── modhyobitto-form-field.component.spec.ts │ │ │ └── modhyobitto-form-field.component.ts │ │ ├── modhyobitto-table │ │ │ ├── modhyobitto-table.component.html │ │ │ ├── modhyobitto-table.component.scss │ │ │ ├── modhyobitto-table.component.spec.ts │ │ │ └── modhyobitto-table.component.ts │ │ └── shared-utilities.module.ts │ │ ├── feature-module-a │ │ ├── feature-module-a-container.component.html │ │ ├── feature-module-a-container.component.scss │ │ ├── feature-module-a-container.component.spec.ts │ │ ├── feature-module-a-container.component.ts │ │ ├── feature-module-a-routing.module.ts │ │ ├── feature-module-a.module.ts │ │ ├── feature-module-a.service.ts │ │ ├── page-a1 │ │ │ ├── page-a1.component.html │ │ │ ├── page-a1.component.scss │ │ │ ├── page-a1.component.spec.ts │ │ │ └── page-a1.component.ts │ │ ├── page-a2 │ │ │ ├── page-a2.component.html │ │ │ ├── page-a2.component.scss │ │ │ ├── page-a2.component.spec.ts │ │ │ └── page-a2.component.ts │ │ ├── page-a3 │ │ │ ├── page-a3.component.html │ │ │ ├── page-a3.component.scss │ │ │ ├── page-a3.component.spec.ts │ │ │ └── page-a3.component.ts │ │ └── page-a4 │ │ │ ├── page-a4.component.html │ │ │ ├── page-a4.component.scss │ │ │ ├── page-a4.component.spec.ts │ │ │ └── page-a4.component.ts │ │ └── feature-module-b │ │ ├── feature-module-b-container.component.html │ │ ├── feature-module-b-container.component.scss │ │ ├── feature-module-b-container.component.spec.ts │ │ ├── feature-module-b-container.component.ts │ │ ├── feature-module-b-routing.module.ts │ │ ├── feature-module-b.module.ts │ │ ├── feature-module-b.service.ts │ │ ├── page-b5 │ │ ├── page-b5.component.html │ │ ├── page-b5.component.scss │ │ ├── page-b5.component.spec.ts │ │ └── page-b5.component.ts │ │ ├── page-b6 │ │ ├── page-b6.component.html │ │ ├── page-b6.component.scss │ │ ├── page-b6.component.spec.ts │ │ └── page-b6.component.ts │ │ ├── page-b7 │ │ ├── page-b7.component.html │ │ ├── page-b7.component.scss │ │ ├── page-b7.component.spec.ts │ │ └── page-b7.component.ts │ │ └── page-b8 │ │ ├── page-b8.component.html │ │ ├── page-b8.component.scss │ │ ├── page-b8.component.spec.ts │ │ └── page-b8.component.ts ├── assets │ ├── .gitkeep │ ├── JSONs │ │ ├── file_download.json │ │ ├── file_upload.json │ │ ├── loginservice.json │ │ ├── table_row_add.json │ │ └── table_row_edit.json │ ├── fonts │ │ ├── Roboto-Bold.eot │ │ ├── Roboto-Bold.svg │ │ ├── Roboto-Bold.ttf │ │ ├── Roboto-Bold.woff │ │ ├── Roboto-Bold.woff2 │ │ ├── Roboto-Light.eot │ │ ├── Roboto-Light.svg │ │ ├── Roboto-Light.ttf │ │ ├── Roboto-Light.woff │ │ ├── Roboto-Light.woff2 │ │ ├── Roboto-Regular.eot │ │ ├── Roboto-Regular.svg │ │ ├── Roboto-Regular.ttf │ │ ├── Roboto-Regular.woff │ │ ├── Roboto-Regular.woff2 │ │ ├── RobotoMono-Regular.eot │ │ ├── RobotoMono-Regular.svg │ │ ├── RobotoMono-Regular.ttf │ │ ├── RobotoMono-Regular.woff │ │ ├── RobotoMono-Regular.woff2 │ │ ├── modhyobitto-icons.eot │ │ ├── modhyobitto-icons.svg │ │ ├── modhyobitto-icons.ttf │ │ └── modhyobitto-icons.woff │ └── images │ │ └── logo-nav@2x.png ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── main.ts ├── polyfills.ts ├── styles.scss ├── styles │ ├── _base_elements.scss │ ├── _font_families.scss │ ├── _global_styles.scss │ ├── _material_theme.scss │ ├── _modhyobitto_icons.scss │ ├── _module_importer.scss │ ├── _variables.scss │ └── modules │ │ ├── _feature_module_a.scss │ │ └── _feature_module_b.scss └── test.ts ├── tsconfig.app.json ├── tsconfig.json └── tsconfig.spec.json /.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line. 18 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://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 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "modhyobitto-angular" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.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 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events*.json 15 | 16 | # IDEs and editors 17 | /.idea 18 | .project 19 | .classpath 20 | .c9/ 21 | *.launch 22 | .settings/ 23 | *.sublime-workspace 24 | 25 | # IDE - VSCode 26 | .vscode/* 27 | !.vscode/settings.json 28 | !.vscode/tasks.json 29 | !.vscode/launch.json 30 | !.vscode/extensions.json 31 | .history/* 32 | 33 | # misc 34 | /.sass-cache 35 | /connect.lock 36 | /coverage 37 | /libpeerconnection.log 38 | npm-debug.log 39 | yarn-error.log 40 | testem.log 41 | /typings 42 | 43 | # System Files 44 | .DS_Store 45 | Thumbs.db 46 | 47 | # Firebase Cache 48 | .firebase/*.cache -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ModhyobittoAngular 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.0.1. 4 | 5 | This codebase was prepared as a project to put together all the little aha moments encountered while working on Angular over the years. This is hardly "the best" way to setup an Angular codebase (in case there can be a "best" way for anything this subjective) and it doesn't claim to be so. 6 | 7 | I have prepared a detailed guide on how to set up and navigate the codebase: 8 | 9 | - [Introduction to optimized Angular codebase setup](https://owrrpon.medium.com/introduction-to-optimized-angular-codebase-setup-d60552dcb59a) 10 | - [Part 1 — Angular Component and Routing Setup](https://owrrpon.medium.com/optimized-angular-component-and-routing-setup-f39d675ac3dc) 11 | - [Part 2 — Styling Framework Setup](https://owrrpon.medium.com/optimized-styling-framework-setup-for-angular-add6646b19d9) 12 | - [Part 3 — Including Angular Material](https://owrrpon.medium.com/optimized-angular-material-setup-21ea8ea2b8) 13 | - [Part 4 — Service/ API Integration](https://owrrpon.medium.com/optimized-service-api-integration-for-angular-476eac8dc5c9) 14 | 15 | 16 | That being said, I keep updating this repo beyond what is mentioned in the above guide. 17 | 18 | The idea is to help others and me in easily bootstrapping a practical Angular application. Knowing a framework is one thing and structuring a codebase is quite another. There is no "one perfect" way of doing things. This is simply the one that has helped me in developing applications that had clean codebases, were easy to manage and fun to develop. 19 | 20 | 21 | ## Development server 22 | 23 | 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. 24 | 25 | 26 | ## Working Example 27 | 28 | You can visit [angular.owrrpon.dev](https://angular.owrrpon.dev/) for the latest working sample Angular application based on the code in this repo. -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "modhyobitto-angular": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "style": "scss" 11 | }, 12 | "@schematics/angular:application": { 13 | "strict": true 14 | } 15 | }, 16 | "root": "", 17 | "sourceRoot": "src", 18 | "prefix": "app", 19 | "architect": { 20 | "build": { 21 | "builder": "@angular-devkit/build-angular:browser", 22 | "options": { 23 | "outputPath": "dist/modhyobitto-angular", 24 | "index": "src/index.html", 25 | "main": "src/main.ts", 26 | "polyfills": "src/polyfills.ts", 27 | "tsConfig": "tsconfig.app.json", 28 | "inlineStyleLanguage": "scss", 29 | "assets": [ 30 | "src/favicon.ico", 31 | "src/assets" 32 | ], 33 | "styles": [ 34 | "src/styles.scss" 35 | ], 36 | "scripts": [] 37 | }, 38 | "configurations": { 39 | "production": { 40 | "budgets": [ 41 | { 42 | "type": "initial", 43 | "maximumWarning": "500kb", 44 | "maximumError": "2mb" 45 | }, 46 | { 47 | "type": "anyComponentStyle", 48 | "maximumWarning": "2kb", 49 | "maximumError": "4kb" 50 | } 51 | ], 52 | "fileReplacements": [ 53 | { 54 | "replace": "src/environments/environment.ts", 55 | "with": "src/environments/environment.prod.ts" 56 | } 57 | ], 58 | "outputHashing": "all" 59 | }, 60 | "development": { 61 | "buildOptimizer": false, 62 | "optimization": false, 63 | "vendorChunk": true, 64 | "extractLicenses": false, 65 | "sourceMap": true, 66 | "namedChunks": true 67 | } 68 | }, 69 | "defaultConfiguration": "production" 70 | }, 71 | "serve": { 72 | "builder": "@angular-devkit/build-angular:dev-server", 73 | "configurations": { 74 | "production": { 75 | "browserTarget": "modhyobitto-angular:build:production" 76 | }, 77 | "development": { 78 | "browserTarget": "modhyobitto-angular:build:development" 79 | } 80 | }, 81 | "defaultConfiguration": "development" 82 | }, 83 | "extract-i18n": { 84 | "builder": "@angular-devkit/build-angular:extract-i18n", 85 | "options": { 86 | "browserTarget": "modhyobitto-angular:build" 87 | } 88 | }, 89 | "test": { 90 | "builder": "@angular-devkit/build-angular:karma", 91 | "options": { 92 | "main": "src/test.ts", 93 | "polyfills": "src/polyfills.ts", 94 | "tsConfig": "tsconfig.spec.json", 95 | "karmaConfig": "karma.conf.js", 96 | "inlineStyleLanguage": "scss", 97 | "assets": [ 98 | "src/favicon.ico", 99 | "src/assets" 100 | ], 101 | "styles": [ 102 | "src/styles.scss" 103 | ], 104 | "scripts": [] 105 | } 106 | } 107 | } 108 | } 109 | }, 110 | "defaultProject": "modhyobitto-angular" 111 | } 112 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "dist/modhyobitto-angular", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /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-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | jasmine: { 17 | // you can add configuration options for Jasmine here 18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html 19 | // for example, you can disable the random execution with `random: false` 20 | // or set a specific seed with `seed: 4321` 21 | }, 22 | clearContext: false // leave Jasmine Spec Runner output visible in browser 23 | }, 24 | jasmineHtmlReporter: { 25 | suppressAll: true // removes the duplicated traces 26 | }, 27 | coverageReporter: { 28 | dir: require('path').join(__dirname, './coverage/modhyobitto-angular'), 29 | subdir: '.', 30 | reporters: [ 31 | { type: 'html' }, 32 | { type: 'text-summary' } 33 | ] 34 | }, 35 | reporters: ['progress', 'kjhtml'], 36 | port: 9876, 37 | colors: true, 38 | logLevel: config.LOG_INFO, 39 | autoWatch: true, 40 | browsers: ['Chrome'], 41 | singleRun: false, 42 | restartOnFileChange: true 43 | }); 44 | }; 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "modhyobitto-angular", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "watch": "ng build --watch --configuration development", 9 | "test": "ng test" 10 | }, 11 | "private": true, 12 | "dependencies": { 13 | "@angular/animations": "~12.0.1", 14 | "@angular/cdk": "^12.0.2", 15 | "@angular/common": "~12.0.1", 16 | "@angular/compiler": "~12.0.1", 17 | "@angular/core": "~12.0.1", 18 | "@angular/forms": "~12.0.1", 19 | "@angular/material": "^12.0.2", 20 | "@angular/platform-browser": "~12.0.1", 21 | "@angular/platform-browser-dynamic": "~12.0.1", 22 | "@angular/router": "~12.0.1", 23 | "bootstrap": "^5.0.1", 24 | "file-saver": "^2.0.5", 25 | "rxjs": "~6.6.0", 26 | "tslib": "^2.1.0", 27 | "zone.js": "~0.11.4" 28 | }, 29 | "devDependencies": { 30 | "@angular-devkit/build-angular": "~12.0.1", 31 | "@angular/cli": "~12.0.1", 32 | "@angular/compiler-cli": "~12.0.1", 33 | "@types/file-saver": "^2.0.2", 34 | "@types/jasmine": "~3.6.0", 35 | "@types/node": "^12.11.1", 36 | "jasmine-core": "~3.7.0", 37 | "karma": "~6.3.0", 38 | "karma-chrome-launcher": "~3.1.0", 39 | "karma-coverage": "~2.0.3", 40 | "karma-jasmine": "~4.0.0", 41 | "karma-jasmine-html-reporter": "^1.5.0", 42 | "typescript": "~4.2.3" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/app/app-dictionary.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { environment } from '../environments/environment'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class AppDictionaryService { 8 | 9 | // This service contains all the static mappings. 10 | // This is not the central data store and hence, does not store the application state. 11 | 12 | error_messages = { 13 | service_failure: 'Our apologies, this site is experiencing some technical difficulties. Please refresh the page or try again.', 14 | validation: { 15 | percentage: 'Enter a percentage with max 2 decimal places.' 16 | } 17 | }; 18 | 19 | regexes = { 20 | percentage: /^(\d{1,3})(\.\d{1,2})?$/ 21 | }; 22 | 23 | service_URLs: { [key:string]: string } = { 24 | 'login': 'loginservice', 25 | 'file_download': 'file_download', 26 | 'file_upload': 'file_upload', 27 | 'table_row_add': 'table_row_add', 28 | 'table_row_edit': 'table_row_edit' 29 | }; 30 | 31 | // Mapping website host with API host 32 | API_hosts: { [key:string]: string } = { 33 | 'dummyhost': 'dummyhost:8080/AppName/' 34 | }; 35 | 36 | // Mapping website host with environment if needed by the API 37 | environment_mapping = { 38 | 'localhost' : 'DEV' 39 | }; 40 | 41 | settings = { 42 | API_full_hostname : document.location.origin+'/assets/JSONs/' 43 | }; 44 | 45 | constructor() { 46 | // For our sample application here, we have simply considered any environment 47 | // setting "dummy_JSONs" to use the JSON files instead of backend API 48 | if(!environment.dummy_JSONs){ 49 | let api_host = this.API_hosts[document.location.hostname]; 50 | // The API application name wil be as per the backend host 51 | this.settings.API_full_hostname = document.location.protocol+"//"+api_host; 52 | } 53 | } 54 | 55 | getAPI(key: string){ 56 | let complete_URL = this.settings.API_full_hostname+this.service_URLs[key]; 57 | return complete_URL; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/app/app-material-importer.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import {MatTabsModule} from '@angular/material/tabs'; 3 | import {MatInputModule} from '@angular/material/input'; 4 | import {MatSelectModule} from '@angular/material/select'; 5 | import {MatNativeDateModule, MatRippleModule } from '@angular/material/core'; 6 | import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; 7 | import {MatSnackBarModule} from '@angular/material/snack-bar'; 8 | import {MatDatepickerModule} from '@angular/material/datepicker'; 9 | import {MatCheckboxModule} from '@angular/material/checkbox'; 10 | import {MatRadioModule} from '@angular/material/radio'; 11 | import {MatDialogModule} from '@angular/material/dialog'; 12 | import {MatMenuModule} from '@angular/material/menu'; 13 | import {MatExpansionModule} from '@angular/material/expansion'; 14 | import {MatProgressBarModule} from '@angular/material/progress-bar'; 15 | import {MatTooltipModule} from '@angular/material/tooltip'; 16 | import {MatTableModule} from '@angular/material/table'; 17 | import {MatPaginatorModule} from '@angular/material/paginator'; 18 | import {MatSidenavModule} from '@angular/material/sidenav'; 19 | 20 | 21 | const MATERIAL_COMPONENTS = [ 22 | MatTabsModule, 23 | MatInputModule, 24 | MatSelectModule, 25 | MatRippleModule, 26 | MatProgressSpinnerModule, 27 | MatSnackBarModule, 28 | MatDatepickerModule, 29 | MatNativeDateModule, 30 | MatCheckboxModule, 31 | MatRadioModule, 32 | MatDialogModule, 33 | MatMenuModule, 34 | MatExpansionModule, 35 | MatProgressBarModule, 36 | MatTooltipModule, 37 | MatTableModule, 38 | MatPaginatorModule, 39 | MatSidenavModule 40 | ]; 41 | 42 | 43 | @NgModule({ 44 | imports: MATERIAL_COMPONENTS, 45 | exports: MATERIAL_COMPONENTS 46 | }) 47 | export class AppMaterialImporterModule { } 48 | -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { DashboardComponent } from './global-components/dashboard/dashboard.component'; 4 | import { LoginComponent } from './global-components/login/login.component'; 5 | import { SecureContainerComponent } from './global-components/secure-container/secure-container.component'; 6 | 7 | const routes: Routes = [ 8 | { 9 | path: '', 10 | redirectTo: 'login', 11 | pathMatch: 'full' 12 | }, 13 | { 14 | path: 'login', 15 | component: LoginComponent 16 | }, 17 | { 18 | path: 'secure', 19 | component: SecureContainerComponent, 20 | children: [ 21 | { path: '', 22 | redirectTo: '/secure/dashboard', 23 | pathMatch: 'full' 24 | }, 25 | { 26 | path: 'dashboard', 27 | component: DashboardComponent 28 | }, 29 | { 30 | path: 'module-a', 31 | loadChildren: () => import('./modules/feature-module-a/feature-module-a.module').then(m => m.FeatureModuleAModule) 32 | }, 33 | { 34 | path: 'module-b', 35 | loadChildren: () => import('./modules/feature-module-b/feature-module-b.module').then(m => m.FeatureModuleBModule) 36 | }, 37 | { 38 | path: '**', 39 | redirectTo: '/secure/dashboard' 40 | } 41 | ] 42 | }, 43 | { 44 | path: '**', 45 | redirectTo: 'login' 46 | } 47 | 48 | ]; 49 | 50 | @NgModule({ 51 | imports: [RouterModule.forRoot(routes)], 52 | exports: [RouterModule] 53 | }) 54 | export class AppRoutingModule { } 55 | -------------------------------------------------------------------------------- /src/app/app-utility.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Subject, Subscription } from 'rxjs'; 3 | import { finalize } from 'rxjs/operators'; 4 | import { environment } from 'src/environments/environment'; 5 | import { AppDictionaryService } from './app-dictionary.service'; 6 | import { HttpClient } from '@angular/common/http'; 7 | import { Router } from '@angular/router'; 8 | import { FormGroup } from '@angular/forms'; 9 | import { MatSnackBar } from '@angular/material/snack-bar'; 10 | import { MatDialog } from '@angular/material/dialog'; 11 | import { ModhyobittoDialogComponent } from './modules/__shared-utilities/modhyobitto-dialog/modhyobitto-dialog.component'; 12 | import { Overlay } from '@angular/cdk/overlay'; 13 | import { saveAs } from 'file-saver'; 14 | 15 | @Injectable({ 16 | providedIn: 'root' 17 | }) 18 | export class AppUtilityService extends AppDictionaryService { 19 | 20 | private globals: { [key:string]: any } = { 21 | ongoing_request_count: 0, 22 | loading_animation_control: new Subject(), 23 | banner_control: new Subject() 24 | }; 25 | 26 | constructor( 27 | private http: HttpClient, 28 | private router: Router, 29 | private snackbar: MatSnackBar, 30 | private dialog: MatDialog, 31 | private overlay: Overlay 32 | ) { super(); } 33 | 34 | serviceWrapper( 35 | HTTP_method: string, 36 | API_URL: string, 37 | responseProcessing: any, 38 | request_data?: any, 39 | skip_loading_animation?: string 40 | ): Subject { 41 | 42 | let response_subject = new Subject(); 43 | 44 | // If it has not been explicitly mentioned to not show the loader, please show. 45 | if(!!!skip_loading_animation){ 46 | this.globals.ongoing_request_count ++; 47 | this.globals.loading_animation_control.next(true); 48 | } 49 | 50 | // Hide snackbars and banners if any 51 | this.hideSnackbar(); 52 | this.hideBanner(); 53 | 54 | // For local API requests, fetch the JSON file instead 55 | if(!environment.production || environment.dummy_JSONs){ 56 | HTTP_method = 'GET'; 57 | API_URL += '.json'; 58 | } 59 | 60 | this.http.request( 61 | HTTP_method, 62 | API_URL, 63 | request_data 64 | ).pipe( 65 | finalize( 66 | () => { 67 | if(!!!skip_loading_animation){ 68 | if(this.globals.ongoing_request_count > 0){ 69 | this.globals.ongoing_request_count --; 70 | } 71 | // Hiding the loading animation 72 | this.globals.loading_animation_control.next(false); 73 | } 74 | } 75 | ) 76 | ).subscribe( 77 | (response: any) => { 78 | // If this is an error object directly send it across 79 | if(!!response['errorCode']){ 80 | response_subject.error(response); 81 | }else{ 82 | let processed_response = responseProcessing(response); 83 | if(!!processed_response.error){ 84 | response_subject.error(processed_response.error); 85 | }else{ 86 | response_subject.next(processed_response.data); 87 | } 88 | } 89 | }, 90 | (error) => { 91 | let error_object = { 92 | 'message' : this.error_messages.service_failure 93 | }; 94 | response_subject.error(error_object); 95 | } 96 | ); 97 | 98 | return response_subject; 99 | } 100 | 101 | login(user_credentials: any){ 102 | let credentials = {...user_credentials}; 103 | return this.serviceWrapper( 104 | 'POST', 105 | this.getAPI('login'), 106 | (response: any) => { 107 | if(response.responseCode == 200){ 108 | return (user_credentials.username=="error")? 109 | {'error': response}: {'data': response}; 110 | }else{ 111 | return {'error': response}; 112 | } 113 | }, 114 | { 115 | body: credentials 116 | } 117 | ); 118 | } 119 | 120 | downloadFile(){ 121 | return this.serviceWrapper( 122 | 'POST', 123 | this.getAPI('file_download'), 124 | (response: any) => { 125 | let file_name = "dummy_file.pdf"; 126 | saveAs(response, file_name); 127 | return {'data': {'message': 'download success'}}; 128 | }, 129 | { 130 | body: { 131 | 'dummy': 'data' 132 | }, 133 | responseType: "blob" 134 | } 135 | ); 136 | } 137 | 138 | uploadFile(form_data: any, API: string){ 139 | return this.serviceWrapper( 140 | 'POST', 141 | API, 142 | (response: any)=>{ 143 | return {'data': { 'message': response.uploadStatus}}; 144 | }, 145 | { 146 | body: form_data 147 | }, 148 | 'skip_loader_animation' 149 | ); 150 | } 151 | 152 | showBanner(text?: string){ 153 | let options = { 154 | to_show: true, 155 | text: text || this.error_messages.service_failure 156 | }; 157 | this.globals.banner_control.next(options); 158 | } 159 | 160 | hideBanner(){ 161 | let options = { 162 | to_show: false 163 | }; 164 | this.globals.banner_control.next(options); 165 | } 166 | 167 | showSnackbar(message?: string){ 168 | setTimeout(()=>{ 169 | let snackar_ref = this.snackbar.open( 170 | message || this.error_messages.service_failure, 171 | 'OK', 172 | {panelClass: 'modhyobitto-snackbar'}); 173 | this.setGlobalData('global_snackbar',snackar_ref); 174 | },1200); 175 | } 176 | 177 | hideSnackbar(){ 178 | this.getGlobalData('global_snackbar')?.dismiss(); 179 | } 180 | 181 | displayAlertDialog(options?: any){ 182 | let global_options = { 183 | autoFocus: false, 184 | panelClass: 'modhyobitto-dialog-container', 185 | scrollStrategy: this.overlay.scrollStrategies.noop() 186 | }; 187 | let dialog_config = {...global_options, ...options}; 188 | let dialog_ref = this.dialog.open( 189 | ModhyobittoDialogComponent, 190 | dialog_config 191 | ); 192 | return dialog_ref; 193 | } 194 | 195 | toggleFormControls( 196 | form_group: FormGroup, 197 | control_list: string[], 198 | to_enable: boolean){ 199 | let control_count = control_list.length; 200 | for(let i=0; i < control_count; i++){ 201 | let current_control = form_group.get(control_list[i]); 202 | if(to_enable){ 203 | current_control?.enable({emitEvent: false}); 204 | }else{ 205 | current_control?.disable({emitEvent: false}); 206 | } 207 | } 208 | } 209 | 210 | scrollToElement(element_ref: any, offset = 10){ 211 | setTimeout(()=>{ 212 | let is_selector = (typeof element_ref) == 'string'; 213 | let element = (is_selector)? document.querySelector(element_ref) : element_ref; 214 | let scroll_extent = element.getBoundingClientRect().top + window.pageYOffset - offset; 215 | window.scrollTo(0, scroll_extent); 216 | }, 200); 217 | } 218 | 219 | onRouteActivation(){ 220 | window.scrollTo({ 221 | top: 0, 222 | left: 0, 223 | behavior: 'smooth' 224 | }); 225 | } 226 | 227 | navigateToURL(URL: string){ 228 | this.router.navigateByUrl(URL); 229 | } 230 | 231 | /* TODO 232 | getCookie(name: string){ 233 | return this.cookieService.get(name); 234 | } 235 | 236 | setCookie(name, value){ 237 | this.cookieService.set(name, value, {path: '/', expires: new Date('12/31/9999')}); 238 | } 239 | 240 | deleteCookie(name){ 241 | this.cookieService.delete(name); 242 | } 243 | 244 | */ 245 | 246 | unsubscribeAll(subs: Subscription[]){ 247 | let sub_count = subs.length; 248 | for(let i=0; i < sub_count; i++){ 249 | let current_sub = subs[i]; 250 | if(!!current_sub){ 251 | current_sub.unsubscribe(); 252 | } 253 | } 254 | } 255 | 256 | setGlobalData(key: string, value: any){ 257 | this.globals[key] = value; 258 | } 259 | 260 | getGlobalData(key: string){ 261 | return this.globals[key]; 262 | } 263 | 264 | 265 | } 266 | 267 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |

Loading

5 |
-------------------------------------------------------------------------------- /src/app/app.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/app.component.scss -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async () => { 7 | await TestBed.configureTestingModule({ 8 | imports: [ 9 | RouterTestingModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | }).compileComponents(); 15 | }); 16 | 17 | it('should create the app', () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.componentInstance; 20 | expect(app).toBeTruthy(); 21 | }); 22 | 23 | it(`should have as title 'modhyobitto-angular'`, () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | const app = fixture.componentInstance; 26 | expect(app.title).toEqual('modhyobitto-angular'); 27 | }); 28 | 29 | it('should render title', () => { 30 | const fixture = TestBed.createComponent(AppComponent); 31 | fixture.detectChanges(); 32 | const compiled = fixture.nativeElement; 33 | expect(compiled.querySelector('.content span').textContent).toContain('modhyobitto-angular app is running!'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Component, OnDestroy, OnInit } from '@angular/core'; 2 | import { Subscription } from 'rxjs'; 3 | import { AppUtilityService } from './app-utility.service'; 4 | 5 | @Component({ 6 | selector: 'app-root', 7 | templateUrl: './app.component.html', 8 | styleUrls: ['./app.component.scss'] 9 | }) 10 | export class AppComponent implements OnInit, AfterViewInit, OnDestroy{ 11 | 12 | is_loader_showing: boolean = false; 13 | loading_animation_control_sub!: Subscription; 14 | 15 | constructor( 16 | public global_utilities: AppUtilityService 17 | ){} 18 | 19 | ngOnInit(){} 20 | 21 | ngAfterViewInit(){ 22 | let loader_control = this.global_utilities.getGlobalData('loading_animation_control'); 23 | this.loading_animation_control_sub = loader_control.subscribe( 24 | (to_show: any) => { 25 | // Show if the loader is not being shown already 26 | if(to_show && !this.is_loader_showing){ 27 | this.is_loader_showing = true; 28 | } 29 | // Hide if the loader is being shown and there is no ongoing service call in next few seconds 30 | if(!to_show && this.is_loader_showing){ 31 | let ongoing_call_check_interval = setInterval( 32 | ()=>{ 33 | let ongoing_call_count = this.global_utilities.getGlobalData('ongoing_request_count'); 34 | if(ongoing_call_count == 0){ 35 | this.is_loader_showing = false; 36 | clearInterval(ongoing_call_check_interval); 37 | } 38 | }, 1000 39 | ); 40 | } 41 | } 42 | ); 43 | } 44 | 45 | ngOnDestroy(){ 46 | this.global_utilities.unsubscribeAll([ 47 | this.loading_animation_control_sub 48 | ]); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/app/app.interceptor.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { 3 | HttpRequest, 4 | HttpHandler, 5 | HttpEvent, 6 | HttpInterceptor 7 | } from '@angular/common/http'; 8 | import { Observable } from 'rxjs'; 9 | 10 | @Injectable() 11 | export class AppInterceptor implements HttpInterceptor { 12 | 13 | constructor() {} 14 | 15 | intercept( 16 | request: HttpRequest, 17 | next: HttpHandler): Observable> { 18 | /*// For adding credentials 19 | request = request.clone({ 20 | withCredentials: true 21 | }); 22 | */ 23 | return next.handle(request); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | 4 | import { AppRoutingModule } from './app-routing.module'; 5 | import { AppComponent } from './app.component'; 6 | import { HeaderComponent } from './global-components/header/header.component'; 7 | import { FooterComponent } from './global-components/footer/footer.component'; 8 | import { DashboardComponent } from './global-components/dashboard/dashboard.component'; 9 | import { LoginComponent } from './global-components/login/login.component'; 10 | import { SecureContainerComponent } from './global-components/secure-container/secure-container.component'; 11 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 12 | import { AppMaterialImporterModule } from './app-material-importer.module'; 13 | import { SharedUtilitiesModule } from './modules/__shared-utilities/shared-utilities.module'; 14 | import { ReactiveFormsModule } from '@angular/forms'; 15 | import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; 16 | import { AppInterceptor } from './app.interceptor'; 17 | import { BannerComponent } from './global-components/banner/banner.component'; 18 | 19 | @NgModule({ 20 | declarations: [ 21 | AppComponent, 22 | HeaderComponent, 23 | FooterComponent, 24 | DashboardComponent, 25 | LoginComponent, 26 | SecureContainerComponent, 27 | BannerComponent 28 | ], 29 | imports: [ 30 | BrowserModule, 31 | AppRoutingModule, 32 | BrowserAnimationsModule, 33 | AppMaterialImporterModule, 34 | SharedUtilitiesModule, 35 | ReactiveFormsModule, 36 | HttpClientModule 37 | ], 38 | providers: [ 39 | { 40 | provide: HTTP_INTERCEPTORS, useClass: AppInterceptor, multi: true 41 | } 42 | ], 43 | bootstrap: [AppComponent] 44 | }) 45 | export class AppModule { } 46 | -------------------------------------------------------------------------------- /src/app/app.validators.ts: -------------------------------------------------------------------------------- 1 | import { AbstractControl } from "@angular/forms"; 2 | import { AppUtilityService } from "./app-utility.service"; 3 | 4 | 5 | export class CustomValidators { 6 | static validatePercentage(global_utilities: AppUtilityService){ 7 | return (control: AbstractControl) => { 8 | let result = null; 9 | let test_regex = global_utilities.regexes.percentage; 10 | if(!!control.value && (!test_regex.test(control.value) || control.value>100)){ 11 | result = { 12 | message: global_utilities.error_messages.validation.percentage 13 | }; 14 | } 15 | 16 | return result; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/app/global-components/banner/banner.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/global-components/banner/banner.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/global-components/banner/banner.component.scss -------------------------------------------------------------------------------- /src/app/global-components/banner/banner.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { BannerComponent } from './banner.component'; 4 | 5 | describe('BannerComponent', () => { 6 | let component: BannerComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ BannerComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(BannerComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/global-components/banner/banner.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnDestroy, OnInit } from '@angular/core'; 2 | import { Subscription } from 'rxjs'; 3 | import { AppUtilityService } from 'src/app/app-utility.service'; 4 | 5 | @Component({ 6 | selector: 'app-banner', 7 | templateUrl: './banner.component.html', 8 | styleUrls: ['./banner.component.scss'] 9 | }) 10 | export class BannerComponent implements OnInit, OnDestroy { 11 | 12 | @Input() is_page_scrolled: boolean = false; 13 | 14 | is_banner_open: boolean = false; 15 | banner_text!: string; 16 | banner_control_sub!: Subscription; 17 | 18 | constructor( 19 | private global_utilities: AppUtilityService 20 | ){} 21 | 22 | ngOnInit(): void { 23 | let banner_control = this.global_utilities.getGlobalData('banner_control'); 24 | this.banner_control_sub = banner_control.subscribe( 25 | (options: any) => { 26 | if(options.to_show){ 27 | setTimeout(()=>{ 28 | this.banner_text = options.text; 29 | this.is_banner_open = true; 30 | },1200); 31 | }else{ 32 | this.dismissBanner(); 33 | } 34 | } 35 | ); 36 | } 37 | 38 | dismissBanner(){ 39 | this.banner_text = ''; 40 | this.is_banner_open = false; 41 | } 42 | 43 | ngOnDestroy(){ 44 | this.global_utilities.unsubscribeAll([ 45 | this.banner_control_sub 46 | ]); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/app/global-components/dashboard/dashboard.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |

Modus Operandi

9 |
10 | 18 | 22 |
23 |
24 |
25 |

Modus Baba Gandhi

26 |
27 | 35 | 39 |
40 |
41 |
42 |
43 |
44 |

Modus Jor Se Praan Di

45 |
46 | 54 | 58 |
59 |
60 | 75 |
76 |
77 |
78 |
79 |
80 |
-------------------------------------------------------------------------------- /src/app/global-components/dashboard/dashboard.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/global-components/dashboard/dashboard.component.scss -------------------------------------------------------------------------------- /src/app/global-components/dashboard/dashboard.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DashboardComponent } from './dashboard.component'; 4 | 5 | describe('DashboardComponent', () => { 6 | let component: DashboardComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ DashboardComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DashboardComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/global-components/dashboard/dashboard.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-dashboard', 5 | templateUrl: './dashboard.component.html', 6 | styleUrls: ['./dashboard.component.scss'] 7 | }) 8 | export class DashboardComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/app/global-components/footer/footer.component.html: -------------------------------------------------------------------------------- 1 |
2 | 45 |
-------------------------------------------------------------------------------- /src/app/global-components/footer/footer.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/global-components/footer/footer.component.scss -------------------------------------------------------------------------------- /src/app/global-components/footer/footer.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FooterComponent } from './footer.component'; 4 | 5 | describe('FooterComponent', () => { 6 | let component: FooterComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ FooterComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FooterComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/global-components/footer/footer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-footer', 5 | templateUrl: './footer.component.html', 6 | styleUrls: ['./footer.component.scss'] 7 | }) 8 | export class FooterComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/app/global-components/header/header.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | modhyobitto 6 | 7 | 10 |
11 |
12 |
13 | 27 |
28 |
29 | 30 | -------------------------------------------------------------------------------- /src/app/global-components/header/header.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/global-components/header/header.component.scss -------------------------------------------------------------------------------- /src/app/global-components/header/header.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HeaderComponent } from './header.component'; 4 | 5 | describe('HeaderComponent', () => { 6 | let component: HeaderComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ HeaderComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HeaderComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/global-components/header/header.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, HostListener } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-header', 5 | templateUrl: './header.component.html', 6 | styleUrls: ['./header.component.scss'] 7 | }) 8 | export class HeaderComponent implements OnInit { 9 | 10 | is_page_scrolled: boolean = false; 11 | 12 | constructor() { } 13 | 14 | ngOnInit(): void { 15 | } 16 | 17 | @HostListener('window:scroll', ['$event.currentTarget.pageYOffset']) 18 | handleStickyNavigation(sroll_distance: Number){ 19 | this.is_page_scrolled = sroll_distance >= 100; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/app/global-components/login/login.component.html: -------------------------------------------------------------------------------- 1 |
2 | 45 |
-------------------------------------------------------------------------------- /src/app/global-components/login/login.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/global-components/login/login.component.scss -------------------------------------------------------------------------------- /src/app/global-components/login/login.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { 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 | await 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/app/global-components/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnDestroy, OnInit } from '@angular/core'; 2 | import { FormControl, FormGroup, Validators } from '@angular/forms'; 3 | import { Subscription } from 'rxjs'; 4 | import { AppUtilityService } from 'src/app/app-utility.service'; 5 | 6 | @Component({ 7 | selector: 'app-login', 8 | templateUrl: './login.component.html', 9 | styleUrls: ['./login.component.scss'] 10 | }) 11 | export class LoginComponent implements OnInit, OnDestroy { 12 | 13 | login_form!: FormGroup; 14 | 15 | // Subscription 16 | private initiate_login_sub!: Subscription; 17 | 18 | constructor( 19 | private global_utilities: AppUtilityService 20 | ) { } 21 | 22 | ngOnInit(): void { 23 | this.login_form = new FormGroup({ 24 | username: new FormControl('', [Validators.required]), 25 | password: new FormControl('', [Validators.required]) 26 | }); 27 | } 28 | 29 | initiateLogin(){ 30 | this.initiate_login_sub = this.global_utilities.login(this.login_form.value).subscribe( 31 | (data)=>{ 32 | this.global_utilities.navigateToURL('/secure'); 33 | }, 34 | (error)=>{ 35 | this.global_utilities.showSnackbar(); 36 | } 37 | ); 38 | } 39 | 40 | ngOnDestroy(): void{ 41 | this.global_utilities.unsubscribeAll([ 42 | this.initiate_login_sub 43 | ]); 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/app/global-components/secure-container/secure-container.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 6 |
7 |
8 | 9 |
-------------------------------------------------------------------------------- /src/app/global-components/secure-container/secure-container.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/global-components/secure-container/secure-container.component.scss -------------------------------------------------------------------------------- /src/app/global-components/secure-container/secure-container.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SecureContainerComponent } from './secure-container.component'; 4 | 5 | describe('SecureContainerComponent', () => { 6 | let component: SecureContainerComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ SecureContainerComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SecureContainerComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/global-components/secure-container/secure-container.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { AppUtilityService } from 'src/app/app-utility.service'; 3 | 4 | @Component({ 5 | selector: 'app-secure-container', 6 | templateUrl: './secure-container.component.html', 7 | styleUrls: ['./secure-container.component.scss'] 8 | }) 9 | export class SecureContainerComponent implements OnInit { 10 | 11 | constructor( 12 | public global_utilities: AppUtilityService 13 | ) { } 14 | 15 | ngOnInit(): void { 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/app/modules/__shared-utilities/drag-and-drop-directive/drag-and-drop.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, EventEmitter, HostBinding, HostListener, Output } from '@angular/core'; 2 | 3 | @Directive({ 4 | selector: '[dragAndDrop]' 5 | }) 6 | export class DragAndDropDirective { 7 | 8 | @Output() onFileDropped = new EventEmitter(); 9 | @HostBinding('style.opacity') private workspace_opacity = '1'; 10 | 11 | // Dragover listener, when files are dragged over our host element 12 | @HostListener('dragover', ['$event']) onDragOver(event: DragEvent) { 13 | event.preventDefault(); 14 | event.stopPropagation(); 15 | this.workspace_opacity = '0.5'; 16 | } 17 | 18 | // Dragleave listener, when files are dragged away from our host element 19 | @HostListener('dragleave', ['$event']) public onDragLeave(event: DragEvent) { 20 | event.preventDefault(); 21 | event.stopPropagation(); 22 | this.workspace_opacity = '1'; 23 | } 24 | 25 | //Drop listener, when files are dropped on our host element 26 | @HostListener('drop', ['$event']) public ondrop(event: DragEvent) { 27 | event.preventDefault(); 28 | event.stopPropagation(); 29 | this.workspace_opacity = '1'; 30 | let files = event.dataTransfer!.files; 31 | if (files.length > 0) { 32 | this.onFileDropped.emit(files) 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/app/modules/__shared-utilities/modhyobitto-dialog/modhyobitto-dialog.component.html: -------------------------------------------------------------------------------- 1 |
2 |

{{data.title}}

3 | 4 | {{data.message}} 5 | 6 | 7 | 8 | 9 | 10 | 12 | 13 |
-------------------------------------------------------------------------------- /src/app/modules/__shared-utilities/modhyobitto-dialog/modhyobitto-dialog.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/modules/__shared-utilities/modhyobitto-dialog/modhyobitto-dialog.component.scss -------------------------------------------------------------------------------- /src/app/modules/__shared-utilities/modhyobitto-dialog/modhyobitto-dialog.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ModhyobittoDialogComponent } from './modhyobitto-dialog.component'; 4 | 5 | describe('ModhyobittoDialogComponent', () => { 6 | let component: ModhyobittoDialogComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ ModhyobittoDialogComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ModhyobittoDialogComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/modules/__shared-utilities/modhyobitto-dialog/modhyobitto-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Inject, OnInit } from '@angular/core'; 2 | import { MAT_DIALOG_DATA } from '@angular/material/dialog'; 3 | 4 | @Component({ 5 | selector: 'app-modhyobitto-dialog', 6 | templateUrl: './modhyobitto-dialog.component.html', 7 | styleUrls: ['./modhyobitto-dialog.component.scss'] 8 | }) 9 | export class ModhyobittoDialogComponent implements OnInit { 10 | 11 | constructor( 12 | @Inject(MAT_DIALOG_DATA) public data: any 13 | ) { } 14 | 15 | ngOnInit(): void { 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/app/modules/__shared-utilities/modhyobitto-file-uploader/modhyobitto-file-uploader.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | Drag and drop the file(s) here or click on "Browse Files". 4 |
5 |
6 | 10 | 11 |
12 |
13 | {{selected_file.file.name}} 14 |
15 |
16 | 29 | 38 |
39 |
40 | 41 |
42 |
44 | The file was uploaded successfully. 45 |
46 |
48 | {{selected_file.upload_result}} 49 |
50 |
51 |
52 |
53 |
56 | 60 |
61 | 67 | 68 | 78 | 87 | 88 |
89 |
-------------------------------------------------------------------------------- /src/app/modules/__shared-utilities/modhyobitto-file-uploader/modhyobitto-file-uploader.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/modules/__shared-utilities/modhyobitto-file-uploader/modhyobitto-file-uploader.component.scss -------------------------------------------------------------------------------- /src/app/modules/__shared-utilities/modhyobitto-file-uploader/modhyobitto-file-uploader.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ModhyobittoFileUploaderComponent } from './modhyobitto-file-uploader.component'; 4 | 5 | describe('ModhyobittoFileUploaderComponent', () => { 6 | let component: ModhyobittoFileUploaderComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ ModhyobittoFileUploaderComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ModhyobittoFileUploaderComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/modules/__shared-utilities/modhyobitto-file-uploader/modhyobitto-file-uploader.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; 2 | import { FormControl, FormGroup } from '@angular/forms'; 3 | import { Subscription } from 'rxjs'; 4 | import { AppUtilityService } from 'src/app/app-utility.service'; 5 | 6 | @Component({ 7 | selector: 'app-modhyobitto-file-uploader', 8 | templateUrl: './modhyobitto-file-uploader.component.html', 9 | styleUrls: ['./modhyobitto-file-uploader.component.scss'] 10 | }) 11 | export class ModhyobittoFileUploaderComponent implements OnInit, OnDestroy { 12 | 13 | @Input() config!: { 14 | API: string, 15 | MIME_types_accepted: string, 16 | is_multiple_selection_allowed: boolean, 17 | data: any 18 | }; 19 | 20 | selected_files: { 21 | file: any, 22 | is_upload_in_progress: boolean, 23 | upload_result: any 24 | }[] = []; 25 | 26 | @ViewChild("fileSelector", {static: false}) file_selector!: ElementRef; 27 | 28 | file_selection_form: FormGroup; 29 | 30 | // Subscriptions 31 | private file_selection_sub!: Subscription; 32 | private file_upload_sub!: Subscription; 33 | 34 | constructor( 35 | private global_utilities: AppUtilityService 36 | ) { 37 | this.file_selection_form = new FormGroup({ 38 | file_selection: new FormControl() 39 | }); 40 | } 41 | 42 | ngOnInit(): void { 43 | this.trackFileSelection(); 44 | } 45 | 46 | openFileSelector(){ 47 | const file_selection = this.file_selector.nativeElement; 48 | file_selection.click(); 49 | } 50 | 51 | trackFileSelection(){ 52 | this.file_selection_sub = this.file_selection_form.get('file_selection')?.valueChanges.subscribe( 53 | ()=>{ 54 | const file_selection = this.file_selector.nativeElement; 55 | this.selectFiles(file_selection.files); 56 | this.file_selector.nativeElement.value = ''; 57 | } 58 | ) as Subscription; 59 | } 60 | 61 | selectFiles(incoming_files: any[]){ 62 | let incoming_file_count = incoming_files.length; 63 | let incorrect_MIME_type = false; 64 | for(let i = 0; i < incoming_file_count; i++){ 65 | let incoming_file = incoming_files[i]; 66 | // Checking if MIME type is acceptable 67 | if(!!!this.config.MIME_types_accepted || this.config.MIME_types_accepted.indexOf(incoming_file.type)>=0){ 68 | let selected_file = { 69 | file: incoming_file, 70 | is_upload_in_progress: false, 71 | upload_result: null 72 | }; 73 | this.selected_files.push(selected_file); 74 | }else{ 75 | incorrect_MIME_type = true; 76 | } 77 | } 78 | // Display error 79 | if(incorrect_MIME_type){ 80 | let message = "Only files of the following MIME types are allowed: "+this.config.MIME_types_accepted; 81 | this.global_utilities.showSnackbar(message); 82 | } 83 | } 84 | 85 | uploadFile(index: number){ 86 | let file_for_upload = this.selected_files[index]; 87 | 88 | const form_data = new FormData(); 89 | form_data.append('file', file_for_upload.file); 90 | 91 | // For other fields, we have to use append() as well 92 | // E.g. form_data.append('thikana', 'Bishadbari Lane'); 93 | 94 | file_for_upload.is_upload_in_progress = true; 95 | file_for_upload.upload_result = null; 96 | 97 | this.file_upload_sub = this.global_utilities.uploadFile(form_data, this.config.API).subscribe( 98 | (success)=>{ 99 | // Dummy setTimeout to imitate API latency 100 | setTimeout(()=>{ 101 | file_for_upload.upload_result=success.message; 102 | 103 | // Adding dummy error 104 | if(file_for_upload.file.name.indexOf('error')>=0){ 105 | file_for_upload.upload_result = this.global_utilities.error_messages.service_failure; 106 | } 107 | 108 | file_for_upload.is_upload_in_progress = false; 109 | },5000); 110 | }, 111 | (error)=>{ 112 | file_for_upload.upload_result=error.message; 113 | file_for_upload.is_upload_in_progress = false; 114 | } 115 | ); 116 | } 117 | 118 | uploadAll(){ 119 | let selected_file_count = this.selected_files.length; 120 | for(let i = 0; i < selected_file_count; i++){ 121 | let selected_file = this.selected_files[i]; 122 | // Checking if the file can be uploaded 123 | if(!selected_file.is_upload_in_progress && selected_file.upload_result!='success'){ 124 | this.uploadFile(i); 125 | } 126 | } 127 | } 128 | 129 | inititateFileCancel(index: number){ 130 | let file_for_upload = this.selected_files[index]; 131 | if(file_for_upload.is_upload_in_progress){ 132 | this.displayFileUploadAbortConfirmation( 133 | ()=>{ 134 | this.cancelFile(index); 135 | } 136 | ); 137 | }else{ 138 | this.cancelFile(index); 139 | } 140 | } 141 | 142 | displayFileUploadAbortConfirmation(cancel_method: any){ 143 | this.global_utilities.displayAlertDialog({ 144 | data:{ 145 | title: "Abort File Upload?", 146 | message: "Upload is already in progress. Aborting now might lead to data inconsistencies.", 147 | dismiss_text: 'Dismiss', 148 | action_text: 'Abort', 149 | action: ()=>{ 150 | cancel_method(); 151 | } 152 | } 153 | }); 154 | } 155 | 156 | cancelFile(index: number){ 157 | this.selected_files.splice(index, 1); 158 | } 159 | 160 | initiateCancelAll(){ 161 | let selected_file_count = this.selected_files.length; 162 | let is_any_file_being_uploaded = false; 163 | for(let i = 0; i < selected_file_count; i++){ 164 | let selected_file = this.selected_files[i]; 165 | // Checking if the file is being uploaded 166 | if(selected_file.is_upload_in_progress){ 167 | is_any_file_being_uploaded = true; 168 | break; 169 | } 170 | } 171 | if(is_any_file_being_uploaded){ 172 | this.displayFileUploadAbortConfirmation( 173 | ()=>{ 174 | this.cancelAll(); 175 | } 176 | ); 177 | }else{ 178 | this.cancelAll(); 179 | } 180 | } 181 | 182 | cancelAll(){ 183 | this.global_utilities.scrollToElement('.modhyobitto-file-uploader', 100); 184 | let selected_file_count = this.selected_files.length; 185 | for(let i = 0; i < selected_file_count; i++){ 186 | this.selected_files.splice(0, 1); 187 | } 188 | } 189 | 190 | isAnyFileNotUploaded(){ 191 | let selected_file_count = this.selected_files.length; 192 | let is_any_file_not_uploaded = false; 193 | for(let i = 0; i < selected_file_count; i++){ 194 | let selected_file = this.selected_files[i]; 195 | // Checking if the file can be uploaded 196 | if(!selected_file.is_upload_in_progress && selected_file.upload_result!='success'){ 197 | is_any_file_not_uploaded = true; 198 | break; 199 | } 200 | } 201 | return is_any_file_not_uploaded; 202 | } 203 | 204 | ngOnDestroy(): void { 205 | this.global_utilities.unsubscribeAll([ 206 | this.file_selection_sub, 207 | this.file_upload_sub 208 | ]); 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /src/app/modules/__shared-utilities/modhyobitto-form-field/modhyobitto-form-field.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | {{label}} 5 | 6 | 7 | 8 | 9 | 10 | 11 | {{key}} 12 | 13 | 14 | 15 | 16 | 20 | 23 | 24 | 25 | 26 | 27 | 28 | 32 | 35 | 39 | 42 | 43 | 44 | 45 | 46 | 51 | 52 | 53 | 54 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | {{control.hasError('required')? 69 | (required_error || 'This field can not be left blank.') 70 | : (control.hasError('message')? 71 | control.getError('message') 72 | : invalid_error)}} 73 | 74 | 75 |
-------------------------------------------------------------------------------- /src/app/modules/__shared-utilities/modhyobitto-form-field/modhyobitto-form-field.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/modules/__shared-utilities/modhyobitto-form-field/modhyobitto-form-field.component.scss -------------------------------------------------------------------------------- /src/app/modules/__shared-utilities/modhyobitto-form-field/modhyobitto-form-field.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ModhyobittoFormFieldComponent } from './modhyobitto-form-field.component'; 4 | 5 | describe('ModhyobittoFormFieldComponent', () => { 6 | let component: ModhyobittoFormFieldComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ ModhyobittoFormFieldComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ModhyobittoFormFieldComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/modules/__shared-utilities/modhyobitto-form-field/modhyobitto-form-field.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnChanges, OnInit } from '@angular/core'; 2 | import { AbstractControl, FormGroup } from '@angular/forms'; 3 | 4 | @Component({ 5 | selector: 'app-modhyobitto-form-field', 6 | templateUrl: './modhyobitto-form-field.component.html', 7 | styleUrls: ['./modhyobitto-form-field.component.scss'] 8 | }) 9 | export class ModhyobittoFormFieldComponent implements OnInit, OnChanges { 10 | 11 | @Input() label!: string; 12 | @Input() required_error!: string; 13 | invalid_error: string = 'Please enter valid data.'; 14 | @Input() placeholder!: string; 15 | @Input() maxlength!: string; 16 | @Input() type: string = "text"; 17 | @Input() select_option_map: any; 18 | select_option_keys!: any[]; 19 | required: boolean = false; 20 | 21 | //for form controls 22 | @Input() parent_FG!: FormGroup; 23 | @Input() control_name!: string; 24 | control!: AbstractControl; 25 | @Input() enddate_control_name!: string; 26 | 27 | constructor() { } 28 | 29 | ngOnInit(): void { 30 | this.control = this.parent_FG.get(this.control_name) as AbstractControl; 31 | 32 | //prepare the select options 33 | if(this.type == 'select'){ 34 | this.select_option_keys = Object.keys(this.select_option_map); 35 | } 36 | 37 | //check if required validator 38 | if(!!this.control.validator){ 39 | let validators = this.control.validator({} as AbstractControl); 40 | this.required = !!validators && !!validators.required; 41 | } 42 | 43 | //update the invalid error for date fields 44 | if(this.type == 'date' || this.type == 'daterange'){ 45 | this.invalid_error = 'Please use MM/DD/YYYY format.'; 46 | } 47 | } 48 | 49 | ngOnChanges(){ 50 | //prepare the select options 51 | if(this.type == 'select'){ 52 | this.select_option_keys = Object.keys(this.select_option_map); 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/app/modules/__shared-utilities/modhyobitto-table/modhyobitto-table.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 26 | 27 | 28 | 29 | 31 |
{{column.heading}} {{table_row[column.key]}} 16 | 25 |
32 |
35 | 46 |
47 | 48 |
-------------------------------------------------------------------------------- /src/app/modules/__shared-utilities/modhyobitto-table/modhyobitto-table.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/modules/__shared-utilities/modhyobitto-table/modhyobitto-table.component.scss -------------------------------------------------------------------------------- /src/app/modules/__shared-utilities/modhyobitto-table/modhyobitto-table.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ModhyobittoTableComponent } from './modhyobitto-table.component'; 4 | 5 | describe('ModhyobittoTableComponent', () => { 6 | let component: ModhyobittoTableComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ ModhyobittoTableComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ModhyobittoTableComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/modules/__shared-utilities/modhyobitto-table/modhyobitto-table.component.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; 2 | import { MatPaginator } from '@angular/material/paginator'; 3 | import { MatTableDataSource } from '@angular/material/table'; 4 | import { Subscription } from 'rxjs'; 5 | import { AppUtilityService } from 'src/app/app-utility.service'; 6 | 7 | @Component({ 8 | selector: 'app-modhyobitto-table', 9 | templateUrl: './modhyobitto-table.component.html', 10 | styleUrls: ['./modhyobitto-table.component.scss'] 11 | }) 12 | export class ModhyobittoTableComponent implements OnInit, AfterViewInit, OnDestroy { 13 | 14 | @Input() table_config: any; 15 | 16 | @Output() onRowAdd = new EventEmitter(); 17 | @Output() onRowEdit = new EventEmitter(); 18 | 19 | displayed_columns!: string[]; 20 | table_data_source: any; 21 | updated_row_index = -1; 22 | 23 | @ViewChild(MatPaginator) paginator!: MatPaginator; 24 | 25 | // Subscriptions 26 | private data_change_sub!: Subscription; 27 | 28 | constructor( 29 | private global_utilities: AppUtilityService 30 | ) { } 31 | 32 | ngOnInit(): void { 33 | this.setDisplayedColumns(this.table_config.columns); 34 | 35 | // if there is any default/static data 36 | this.table_data_source = new MatTableDataSource(this.table_config.default_data); 37 | 38 | if(!!this.table_config.table_data_changer){ 39 | // if there is a scope to update data 40 | this.trackDataChange(); 41 | } 42 | } 43 | 44 | setDisplayedColumns(column_config: any[]){ 45 | let col_count = column_config.length; 46 | let columns_to_display = []; 47 | for(let i = 0; i{ 60 | this.table_data_source = new MatTableDataSource(new_data.data); 61 | this.table_data_source.paginator = this.paginator; 62 | if(!!new_data.highlight){ 63 | //if it is needed to highlight the updated/new row 64 | this.goToUpdatedPage(new_data.highlight, new_data.data); 65 | } 66 | } 67 | ); 68 | } 69 | 70 | goToUpdatedPage(updated_row: any, data: any[]){ 71 | //get the index of the updated row 72 | let updated_index = data.findIndex( 73 | (row)=>{ 74 | let is_matching = true; 75 | let primary_key_count = this.table_config.primary_key_set.length; 76 | for(let i=0; i{ 88 | if(updated_index >= 0){ 89 | let page_size = this.paginator.pageSize; 90 | let current_page_index = this.paginator.pageIndex; 91 | let calculated_page_index = Math.ceil((updated_index + 1)/page_size) - 1; 92 | if(calculated_page_index != current_page_index){ 93 | if(calculated_page_index == 0){ 94 | //if the first page is to be navigated to 95 | this.paginator.pageIndex = 1; 96 | this.paginator.previousPage(); 97 | }else{ 98 | this.paginator.pageIndex = calculated_page_index - 1; 99 | this.paginator.nextPage(); 100 | } 101 | } 102 | this.updated_row_index = updated_index - (page_size * calculated_page_index); 103 | setTimeout(()=>{ 104 | this.updated_row_index = -1; 105 | },4000); 106 | } 107 | },100); 108 | } 109 | 110 | editRow(row: any){ 111 | this.onRowEdit.emit(row); 112 | } 113 | 114 | addRow(){ 115 | this.onRowAdd.emit(); 116 | } 117 | 118 | ngAfterViewInit(): void { 119 | if(!!this.table_data_source){ 120 | this.table_data_source.paginator = this.paginator; 121 | } 122 | } 123 | 124 | ngOnDestroy(): void { 125 | this.global_utilities.unsubscribeAll([ 126 | this.data_change_sub 127 | ]); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/app/modules/__shared-utilities/shared-utilities.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { AppMaterialImporterModule } from 'src/app/app-material-importer.module'; 4 | import { ReactiveFormsModule } from '@angular/forms'; 5 | import { ModhyobittoFormFieldComponent } from './modhyobitto-form-field/modhyobitto-form-field.component'; 6 | import { ModhyobittoDialogComponent } from './modhyobitto-dialog/modhyobitto-dialog.component'; 7 | import { ModhyobittoFileUploaderComponent } from './modhyobitto-file-uploader/modhyobitto-file-uploader.component'; 8 | import { DragAndDropDirective } from './drag-and-drop-directive/drag-and-drop.directive'; 9 | import { ModhyobittoTableComponent } from './modhyobitto-table/modhyobitto-table.component'; 10 | 11 | const UTILITY_COMPONENTS = [ 12 | ModhyobittoFormFieldComponent, 13 | ModhyobittoDialogComponent, 14 | ModhyobittoFileUploaderComponent, 15 | DragAndDropDirective, 16 | ModhyobittoTableComponent 17 | ]; 18 | 19 | 20 | @NgModule({ 21 | imports: [ 22 | CommonModule, 23 | AppMaterialImporterModule, 24 | ReactiveFormsModule 25 | ], 26 | declarations: UTILITY_COMPONENTS, 27 | exports: UTILITY_COMPONENTS 28 | }) 29 | export class SharedUtilitiesModule { } 30 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/feature-module-a-container.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 47 |
48 |
49 |
50 | 51 |
52 |
53 |
54 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/feature-module-a-container.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/modules/feature-module-a/feature-module-a-container.component.scss -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/feature-module-a-container.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FeatureModuleAContainerComponent } from './feature-module-a-container.component'; 4 | 5 | describe('FeatureModuleAContainerComponent', () => { 6 | let component: FeatureModuleAContainerComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ FeatureModuleAContainerComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FeatureModuleAContainerComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/feature-module-a-container.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { AppUtilityService } from 'src/app/app-utility.service'; 3 | 4 | @Component({ 5 | selector: 'app-feature-module-a-container', 6 | templateUrl: './feature-module-a-container.component.html', 7 | styleUrls: ['./feature-module-a-container.component.scss'] 8 | }) 9 | export class FeatureModuleAContainerComponent implements OnInit { 10 | 11 | constructor( 12 | public global_utilities: AppUtilityService 13 | ) { } 14 | 15 | ngOnInit(): void { 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/feature-module-a-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { FeatureModuleAContainerComponent } from './feature-module-a-container.component'; 4 | import { PageA1Component } from './page-a1/page-a1.component'; 5 | import { PageA2Component } from './page-a2/page-a2.component'; 6 | import { PageA3Component } from './page-a3/page-a3.component'; 7 | import { PageA4Component } from './page-a4/page-a4.component'; 8 | 9 | const routes: Routes = [ 10 | { path: '', 11 | redirectTo: 'page-a1', 12 | pathMatch: 'full' 13 | }, 14 | { 15 | path:'', 16 | component: FeatureModuleAContainerComponent, 17 | children: [ 18 | { 19 | path: 'page-a1', 20 | component: PageA1Component 21 | }, 22 | { 23 | path: 'page-a2', 24 | component: PageA2Component 25 | }, 26 | { 27 | path: 'page-a3', 28 | component: PageA3Component 29 | }, 30 | { 31 | path: 'page-a4', 32 | component: PageA4Component 33 | } 34 | ] 35 | } 36 | ]; 37 | 38 | @NgModule({ 39 | imports: [RouterModule.forChild(routes)], 40 | exports: [RouterModule] 41 | }) 42 | export class FeatureModuleARoutingModule { } 43 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/feature-module-a.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | import { FeatureModuleARoutingModule } from './feature-module-a-routing.module'; 5 | import { FeatureModuleAContainerComponent } from './feature-module-a-container.component'; 6 | import { PageA1Component } from './page-a1/page-a1.component'; 7 | import { PageA2Component } from './page-a2/page-a2.component'; 8 | import { PageA3Component } from './page-a3/page-a3.component'; 9 | import { PageA4Component } from './page-a4/page-a4.component'; 10 | import { SharedUtilitiesModule } from '../__shared-utilities/shared-utilities.module'; 11 | import { ReactiveFormsModule } from '@angular/forms'; 12 | import { AppMaterialImporterModule } from 'src/app/app-material-importer.module'; 13 | 14 | 15 | @NgModule({ 16 | declarations: [ 17 | FeatureModuleAContainerComponent, 18 | PageA1Component, 19 | PageA2Component, 20 | PageA3Component, 21 | PageA4Component 22 | ], 23 | imports: [ 24 | CommonModule, 25 | ReactiveFormsModule, 26 | FeatureModuleARoutingModule, 27 | SharedUtilitiesModule, 28 | AppMaterialImporterModule 29 | ] 30 | }) 31 | export class FeatureModuleAModule { } 32 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/feature-module-a.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { AppUtilityService } from 'src/app/app-utility.service'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class FeatureModuleAService { 8 | 9 | private module_data: { [key:string]: any } = {}; 10 | 11 | constructor( 12 | private global_utilities: AppUtilityService 13 | ) { } 14 | 15 | setModuleData(key: string, value: any){ 16 | this.module_data[key] = value; 17 | } 18 | 19 | getModuleData(key: string){ 20 | return this.module_data[key]; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/page-a1/page-a1.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Form Fields

4 |
5 |

6 | I met a girl who sang the blues and I asked her for some happy news but she just smiled and turned away. I went down to the sacred store where I'd heard the music years before but the man there said the music wouldn't play. And in the streets the children screamed. The lovers cried, and the poets dreamed but not a word was spoken. The church bells all were broken and the three men I admire most - the Father, Son and the Holy Ghost. They caught the last train for the coast. The day the music died. 7 |

8 |
9 |
13 |
14 |
15 |
16 | 22 | 23 |
24 |
25 | 31 | 32 |
33 |
34 | 41 | 42 |
43 |
44 | 50 | 51 |
52 |
53 | 59 | 60 |
61 |
62 | 68 | 69 |
70 |
71 | 76 | 77 |
78 |
79 | 85 | 86 |
87 |
88 | 93 | 94 |
95 |
96 |
97 |
Select the options that apply 98 | 99 |
100 |
    101 |
  • 102 | 103 | Checkbox 1 104 | 105 |
  • 106 |
  • 107 | 108 | Checkbox 2 109 | 110 |
  • 111 |
112 | 115 |
116 |
117 |
118 |
119 |
Select the option that apply 120 | 121 |
122 | 123 | Option 1 124 | Option 2 125 | Option 3 126 | Option 4 127 | 128 | 131 |
132 |
133 |
134 |
135 |
136 | 140 | 144 |
145 |
146 |
147 |
148 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/page-a1/page-a1.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/modules/feature-module-a/page-a1/page-a1.component.scss -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/page-a1/page-a1.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PageA1Component } from './page-a1.component'; 4 | 5 | describe('PageA1Component', () => { 6 | let component: PageA1Component; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ PageA1Component ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PageA1Component); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/page-a1/page-a1.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewChild } from '@angular/core'; 2 | import { FormControl, FormGroup, Validators } from '@angular/forms'; 3 | import { AppUtilityService } from 'src/app/app-utility.service'; 4 | import { CustomValidators } from 'src/app/app.validators'; 5 | 6 | @Component({ 7 | selector: 'app-page-a1', 8 | templateUrl: './page-a1.component.html', 9 | styleUrls: ['./page-a1.component.scss'] 10 | }) 11 | export class PageA1Component implements OnInit { 12 | 13 | formfield_demo_form!: FormGroup; 14 | select_option_list = ['Option X', 'Option Y', 'Option Z']; 15 | 16 | @ViewChild('form_ref') ngForm_ref!: any; 17 | 18 | constructor( 19 | private global_utilities: AppUtilityService 20 | ) { } 21 | 22 | ngOnInit(): void { 23 | this.formfield_demo_form = new FormGroup({ 24 | text: new FormControl(), 25 | required_text: new FormControl('',[Validators.required]), 26 | custom_required_text: new FormControl('',[Validators.required]), 27 | generic_validation: new FormControl('',[Validators.max(10)]), 28 | custom_validation: new FormControl('',[CustomValidators.validatePercentage(this.global_utilities)]), 29 | select: new FormControl(), 30 | date: new FormControl(), 31 | start_date: new FormControl(), 32 | end_date: new FormControl(), 33 | textarea: new FormControl(), 34 | checkbox1: new FormControl(false), 35 | checkbox2: new FormControl(false), 36 | radio: new FormControl() 37 | }); 38 | } 39 | 40 | resetDemoForm(){ 41 | this.formfield_demo_form.reset(); 42 | } 43 | 44 | initiateDemoSubmit(){ 45 | //this.ngForm_ref.resetForm(); 46 | this.formfield_demo_form.reset(); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/page-a2/page-a2.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Banners and Snackbars

4 |
5 |

6 | I met a girl who sang the blues and I asked her for some happy news but she just smiled and turned away. I went down to the sacred store where I'd heard the music years before but the man there said the music wouldn't play. And in the streets the children screamed. The lovers cried, and the poets dreamed but not a word was spoken. The church bells all were broken and the three men I admire most - the Father, Son and the Holy Ghost. They caught the last train for the coast. The day the music died. 7 |

8 |
9 | 10 | 11 |
12 |
13 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/page-a2/page-a2.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/modules/feature-module-a/page-a2/page-a2.component.scss -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/page-a2/page-a2.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PageA2Component } from './page-a2.component'; 4 | 5 | describe('PageA2Component', () => { 6 | let component: PageA2Component; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ PageA2Component ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PageA2Component); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/page-a2/page-a2.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnDestroy, OnInit } from '@angular/core'; 2 | import { Subscription } from 'rxjs'; 3 | import { AppUtilityService } from 'src/app/app-utility.service'; 4 | 5 | @Component({ 6 | selector: 'app-page-a2', 7 | templateUrl: './page-a2.component.html', 8 | styleUrls: ['./page-a2.component.scss'] 9 | }) 10 | export class PageA2Component implements OnInit, OnDestroy { 11 | 12 | // Subscription 13 | private initiate_login_sub!: Subscription; 14 | 15 | constructor( 16 | private global_utilities: AppUtilityService 17 | ){} 18 | 19 | ngOnInit(): void { 20 | } 21 | 22 | openCommunication(type: string){ 23 | let cred = { 24 | username: 'error', 25 | password: 'error' 26 | }; 27 | this.initiate_login_sub = this.global_utilities.login(cred).subscribe( 28 | (data)=>{ 29 | //NOOP 30 | }, 31 | (error)=>{ 32 | switch (type) { 33 | case 'banner': 34 | this.global_utilities.showBanner(); 35 | break; 36 | 37 | case 'snackbar': 38 | this.global_utilities.showSnackbar(); 39 | break; 40 | } 41 | } 42 | ); 43 | } 44 | 45 | ngOnDestroy(): void{ 46 | this.global_utilities.unsubscribeAll([ 47 | this.initiate_login_sub 48 | ]); 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/page-a3/page-a3.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Dialogs

4 |
5 |

6 | Now, for ten years we've been on our own and moss grows fat on a rollin' stone but that's not how it used to be. When the jester sang for the king and queen in a coat he borrowed from James Dean and a voice that came from you and me. Oh, and while the king was looking down the jester stole his thorny crown. The courtroom was adjourned. No verdict was returned. And while Lenin read a book on Marx. A quartet practiced in the park and we sang dirges in the dark. The day the music died. 7 |

8 |
9 | 10 | 11 |
12 |
13 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/page-a3/page-a3.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/modules/feature-module-a/page-a3/page-a3.component.scss -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/page-a3/page-a3.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PageA3Component } from './page-a3.component'; 4 | 5 | describe('PageA3Component', () => { 6 | let component: PageA3Component; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ PageA3Component ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PageA3Component); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/page-a3/page-a3.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { AppUtilityService } from 'src/app/app-utility.service'; 3 | 4 | @Component({ 5 | selector: 'app-page-a3', 6 | templateUrl: './page-a3.component.html', 7 | styleUrls: ['./page-a3.component.scss'] 8 | }) 9 | export class PageA3Component implements OnInit { 10 | 11 | constructor( 12 | private global_utilities: AppUtilityService 13 | ) { } 14 | 15 | ngOnInit(): void { 16 | } 17 | 18 | openAlertDialog(){ 19 | this.global_utilities.displayAlertDialog({ 20 | data:{ 21 | title: "Everything's Not Lost", 22 | message: "If you ever feel neglected, if you think all is lost, I'll be counting up my demons (yeah) hoping everything's not lost." 23 | } 24 | }); 25 | } 26 | 27 | openConfirmationDialog(){ 28 | this.global_utilities.displayAlertDialog({ 29 | data:{ 30 | title: "What Will Become Of Us?", 31 | message: "For they'll pour cement down this hole of ours and we'll be stuck under stones and flowers. Will we go alone out on our own? Oh, darling that's what will become of us?", 32 | dismiss_text: 'Dismiss', 33 | action_text: 'Concrete', 34 | action: ()=>{ 35 | this.global_utilities.showSnackbar('We will bite our noses off to spite our faces, both of us will rust like metal fences in the rain.'); 36 | } 37 | } 38 | }); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/page-a4/page-a4.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

File Download

4 |
5 |

6 | Now, for ten years we've been on our own and moss grows fat on a rollin' stone but that's not how it used to be. When the jester sang for the king and queen in a coat he borrowed from James Dean and a voice that came from you and me. Oh, and while the king was looking down the jester stole his thorny crown. The courtroom was adjourned. No verdict was returned. And while Lenin read a book on Marx. A quartet practiced in the park and we sang dirges in the dark. The day the music died. 7 |

8 |
9 | 10 |
11 |
12 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/page-a4/page-a4.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/modules/feature-module-a/page-a4/page-a4.component.scss -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/page-a4/page-a4.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PageA4Component } from './page-a4.component'; 4 | 5 | describe('PageA4Component', () => { 6 | let component: PageA4Component; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ PageA4Component ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PageA4Component); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-a/page-a4/page-a4.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnDestroy, OnInit } from '@angular/core'; 2 | import { Subscription } from 'rxjs'; 3 | import { AppUtilityService } from 'src/app/app-utility.service'; 4 | 5 | @Component({ 6 | selector: 'app-page-a4', 7 | templateUrl: './page-a4.component.html', 8 | styleUrls: ['./page-a4.component.scss'] 9 | }) 10 | export class PageA4Component implements OnInit, OnDestroy { 11 | 12 | // Subscription 13 | private file_download_sub!: Subscription; 14 | 15 | constructor( 16 | private global_utilities: AppUtilityService 17 | ){} 18 | 19 | ngOnInit(): void { 20 | } 21 | 22 | downloadFile(){ 23 | this.file_download_sub = this.global_utilities.downloadFile().subscribe( 24 | (data)=>{ 25 | this.global_utilities.showSnackbar('File downloaded successfully!'); 26 | }, 27 | (error)=>{ 28 | this.global_utilities.showBanner(); 29 | } 30 | ); 31 | } 32 | 33 | ngOnDestroy(): void{ 34 | this.global_utilities.unsubscribeAll([ 35 | this.file_download_sub 36 | ]); 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/feature-module-b-container.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 49 |
50 |
51 |
52 | 53 |
54 |
55 |
56 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/feature-module-b-container.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/modules/feature-module-b/feature-module-b-container.component.scss -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/feature-module-b-container.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FeatureModuleBContainerComponent } from './feature-module-b-container.component'; 4 | 5 | describe('FeatureModuleBContainerComponent', () => { 6 | let component: FeatureModuleBContainerComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ FeatureModuleBContainerComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FeatureModuleBContainerComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/feature-module-b-container.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { AppUtilityService } from 'src/app/app-utility.service'; 3 | 4 | @Component({ 5 | selector: 'app-feature-module-b-container', 6 | templateUrl: './feature-module-b-container.component.html', 7 | styleUrls: ['./feature-module-b-container.component.scss'] 8 | }) 9 | export class FeatureModuleBContainerComponent implements OnInit { 10 | 11 | constructor( 12 | public global_utilities: AppUtilityService 13 | ) { } 14 | 15 | ngOnInit(): void { 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/feature-module-b-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { FeatureModuleBContainerComponent } from './feature-module-b-container.component'; 4 | import { PageB5Component } from './page-b5/page-b5.component'; 5 | import { PageB6Component } from './page-b6/page-b6.component'; 6 | import { PageB7Component } from './page-b7/page-b7.component'; 7 | import { PageB8Component } from './page-b8/page-b8.component'; 8 | 9 | const routes: Routes = [ 10 | { path: '', 11 | redirectTo: 'page-b5', 12 | pathMatch: 'full' 13 | }, 14 | { 15 | path:'', 16 | component: FeatureModuleBContainerComponent, 17 | children: [ 18 | { 19 | path: 'page-b5', 20 | component: PageB5Component 21 | }, 22 | { 23 | path: 'page-b6', 24 | component: PageB6Component 25 | }, 26 | { 27 | path: 'page-b7', 28 | component: PageB7Component 29 | }, 30 | { 31 | path: 'page-b8', 32 | component: PageB8Component 33 | } 34 | ] 35 | } 36 | ]; 37 | 38 | @NgModule({ 39 | imports: [RouterModule.forChild(routes)], 40 | exports: [RouterModule] 41 | }) 42 | export class FeatureModuleBRoutingModule { } 43 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/feature-module-b.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | import { FeatureModuleBRoutingModule } from './feature-module-b-routing.module'; 5 | import { FeatureModuleBContainerComponent } from './feature-module-b-container.component'; 6 | import { PageB5Component } from './page-b5/page-b5.component'; 7 | import { PageB6Component } from './page-b6/page-b6.component'; 8 | import { PageB7Component } from './page-b7/page-b7.component'; 9 | import { PageB8Component } from './page-b8/page-b8.component'; 10 | import { AppMaterialImporterModule } from 'src/app/app-material-importer.module'; 11 | import { ReactiveFormsModule } from '@angular/forms'; 12 | import { SharedUtilitiesModule } from '../__shared-utilities/shared-utilities.module'; 13 | 14 | 15 | @NgModule({ 16 | declarations: [ 17 | FeatureModuleBContainerComponent, 18 | PageB5Component, 19 | PageB6Component, 20 | PageB7Component, 21 | PageB8Component 22 | ], 23 | imports: [ 24 | CommonModule, 25 | ReactiveFormsModule, 26 | FeatureModuleBRoutingModule, 27 | SharedUtilitiesModule, 28 | AppMaterialImporterModule 29 | ] 30 | }) 31 | export class FeatureModuleBModule { } 32 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/feature-module-b.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { AppUtilityService } from 'src/app/app-utility.service'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class FeatureModuleBService { 8 | 9 | private module_data: { [key:string]: any } = {}; 10 | 11 | constructor( 12 | private global_utilities: AppUtilityService 13 | ) { } 14 | 15 | updateTableData(row_data:any, is_new_row_being_added:boolean){ 16 | let API_key = is_new_row_being_added? 'table_row_add' : 'table_row_edit'; 17 | return this.global_utilities.serviceWrapper( 18 | 'POST', 19 | this.global_utilities.getAPI(API_key), 20 | (response: any)=>{ 21 | return {'data': response.tableData}; 22 | }, 23 | { 24 | body: row_data 25 | } 26 | ); 27 | } 28 | 29 | setModuleData(key: string, value: any){ 30 | this.module_data[key] = value; 31 | } 32 | 33 | getModuleData(key: string){ 34 | return this.module_data[key]; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/page-b5/page-b5.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

File Uploader

4 |
5 |

6 | Oh, and there we were all in one place, a generation lost in space with no time left to start again. So, come on, Jack be nimble, Jack be quick. Jack Flash sat on a candlestick 'cause fire is the Devil's only friend. Oh, and as I watched him on the stage my hands were clenched in fists of rage. No angel born in Hell could break that Satan spell. And as the flames climbed high into the night to light the sacrificial rite, I saw Satan laughing with delight. The day the music died. 7 |

8 |
9 | 11 | 12 |
13 |
14 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/page-b5/page-b5.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/modules/feature-module-b/page-b5/page-b5.component.scss -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/page-b5/page-b5.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PageB5Component } from './page-b5.component'; 4 | 5 | describe('PageB5Component', () => { 6 | let component: PageB5Component; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ PageB5Component ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PageB5Component); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/page-b5/page-b5.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { AppUtilityService } from 'src/app/app-utility.service'; 3 | 4 | @Component({ 5 | selector: 'app-page-b5', 6 | templateUrl: './page-b5.component.html', 7 | styleUrls: ['./page-b5.component.scss'] 8 | }) 9 | export class PageB5Component implements OnInit { 10 | 11 | file_upload_config = { 12 | API: this.global_utilities.getAPI('file_upload'), 13 | MIME_types_accepted: "application/pdf", 14 | is_multiple_selection_allowed: true, 15 | data: null 16 | }; 17 | 18 | constructor( 19 | private global_utilities: AppUtilityService 20 | ) { } 21 | 22 | ngOnInit(): void { 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/page-b6/page-b6.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Basic Table

4 |
5 |

6 | Oh, and there we were all in one place, a generation lost in space with no time left to start again. So, come on, Jack be nimble, Jack be quick. Jack Flash sat on a candlestick 'cause fire is the Devil's only friend. Oh, and as I watched him on the stage my hands were clenched in fists of rage. No angel born in Hell could break that Satan spell. And as the flames climbed high into the night to light the sacrificial rite, I saw Satan laughing with delight. The day the music died. 7 |

8 |
9 | 10 |
11 |
12 | 13 |
14 |
15 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/page-b6/page-b6.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/modules/feature-module-b/page-b6/page-b6.component.scss -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/page-b6/page-b6.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PageB6Component } from './page-b6.component'; 4 | 5 | describe('PageB6Component', () => { 6 | let component: PageB6Component; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ PageB6Component ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PageB6Component); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/page-b6/page-b6.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Subject } from 'rxjs'; 3 | 4 | @Component({ 5 | selector: 'app-page-b6', 6 | templateUrl: './page-b6.component.html', 7 | styleUrls: ['./page-b6.component.scss'] 8 | }) 9 | export class PageB6Component implements OnInit { 10 | 11 | table_config = { 12 | columns: [ 13 | { 14 | key: 'a', 15 | heading: 'Column A' 16 | }, 17 | { 18 | key: 'b', 19 | heading: 'Column B' 20 | }, 21 | { 22 | key: 'c', 23 | heading: 'Column C', 24 | numeric: true 25 | } 26 | ], 27 | default_data: DUMMY_TABLE_DATA, 28 | table_data_changer: new Subject() 29 | }; 30 | 31 | constructor() { } 32 | 33 | ngOnInit(): void { 34 | 35 | } 36 | 37 | updateTableData(){ 38 | this.table_config.table_data_changer.next({ 39 | data: DUMMY_TABLE_DATA2 40 | }); 41 | } 42 | 43 | } 44 | 45 | const DUMMY_TABLE_DATA: any[]= [ 46 | { a: 'Dummy1', b: 'Data String 1', c: 21}, 47 | { a: 'Dummy2', b: 'Data String 2', c: 22}, 48 | { a: 'Dummy3', b: 'Data String 3', c: 23}, 49 | { a: 'Dummy4', b: 'Data String 4', c: 24}, 50 | { a: 'Dummy5', b: 'Data String 5', c: 25}, 51 | { a: 'Dummy6', b: 'Data String 6', c: 26}, 52 | { a: 'Dummy7', b: 'Data String 7', c: 27}, 53 | { a: 'Dummy8', b: 'Data String 8', c: 28}, 54 | { a: 'Dummy9', b: 'Data String 9', c: 29}, 55 | { a: 'Dummy10', b: 'Data String 10', c: 30}, 56 | { a: 'Dummy11', b: 'Data String 11', c: 31}, 57 | { a: 'Dummy12', b: 'Data String 12', c: 32}, 58 | { a: 'Dummy13', b: 'Data String 13', c: 33}, 59 | { a: 'Dummy14', b: 'Data String 14', c: 34}, 60 | { a: 'Dummy15', b: 'Data String 15', c: 35}, 61 | { a: 'Dummy16', b: 'Data String 16', c: 36}, 62 | { a: 'Dummy17', b: 'Data String 17', c: 37}, 63 | { a: 'Dummy18', b: 'Data String 18', c: 38}, 64 | { a: 'Dummy19', b: 'Data String 19', c: 39}, 65 | { a: 'Dummy20', b: 'Data String 20', c: 40}, 66 | ]; 67 | 68 | const DUMMY_TABLE_DATA2: any[]= [ 69 | { a: 'Updated 1', b: 'Updated String 1', c: 21}, 70 | { a: 'Updated 2', b: 'Updated String 2', c: 22}, 71 | { a: 'Updated 3', b: 'Updated String 3', c: 23}, 72 | { a: 'Updated 4', b: 'Updated String 4', c: 24}, 73 | { a: 'Updated 5', b: 'Updated String 5', c: 25}, 74 | { a: 'Updated 6', b: 'Updated String 6', c: 26}, 75 | { a: 'Updated 7', b: 'Updated String 7', c: 27}, 76 | { a: 'Updated 8', b: 'Updated String 8', c: 28}, 77 | { a: 'Updated 9', b: 'Updated String 9', c: 29}, 78 | { a: 'Updated 10', b: 'Updated String 10', c: 29} 79 | ]; 80 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/page-b7/page-b7.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

EdiTable

4 |
5 |

6 | Did you write the book of love and do you have faith in God above if the Bible tells you so? Now, do you believe in rock 'n' roll? Can music save your mortal soul? And can you teach me how to dance real slow? Well, I know that you're in love with him 'cause I saw you dancin' in the gym. You both kicked off your shoes. Man, I dig those rhythm and blues. I was a lonely teenage bronckin' buck with a pink carnation and a pickup truck but I knew I was out of luck. The day the music died. 7 |

8 |
9 | 10 | 13 |
14 |
17 |
18 |

{{is_new_row_being_added? 'Add New' : 'Edit'}} Row

19 |
20 |
21 |
22 |
23 | 27 | 28 |
29 |
30 | 34 | 35 |
36 |
37 |
38 |
39 | 43 | 44 |
45 |
46 |
47 |
48 |
49 |
50 | 54 |
55 |
56 | 60 |
61 |
62 |
63 |
64 |
65 |
66 | 67 | 71 | 72 | 73 |
74 |
75 |
76 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/page-b7/page-b7.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/modules/feature-module-b/page-b7/page-b7.component.scss -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/page-b7/page-b7.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PageB7Component } from './page-b7.component'; 4 | 5 | describe('PageB7Component', () => { 6 | let component: PageB7Component; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ PageB7Component ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PageB7Component); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/page-b7/page-b7.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core'; 2 | import { FormControl, FormGroup, Validators } from '@angular/forms'; 3 | import { Subject, Subscription } from 'rxjs'; 4 | import { AppUtilityService } from 'src/app/app-utility.service'; 5 | import { FeatureModuleBService } from '../feature-module-b.service'; 6 | 7 | @Component({ 8 | selector: 'app-page-b7', 9 | templateUrl: './page-b7.component.html', 10 | styleUrls: ['./page-b7.component.scss'] 11 | }) 12 | export class PageB7Component implements OnInit, OnDestroy { 13 | 14 | table_config = { 15 | columns: [ 16 | { 17 | key: 'a', 18 | heading: 'Column A' 19 | }, 20 | { 21 | key: 'b', 22 | heading: 'Column B' 23 | }, 24 | { 25 | key: 'c', 26 | heading: 'Column C', 27 | numeric: true 28 | } 29 | ], 30 | primary_key_set: ['a'], 31 | default_data: DUMMY_TABLE_DATA, 32 | table_data_changer: new Subject(), 33 | ediTable: { 34 | add: true, 35 | edit: true 36 | } 37 | }; 38 | 39 | // for table update form 40 | is_table_being_updated: boolean = false; 41 | is_new_row_being_added: boolean = false; 42 | table_update_form!: FormGroup; 43 | existing_row_values!: any; 44 | 45 | // for table update API call 46 | private update_table_data_sub!: Subscription; 47 | 48 | constructor( 49 | private global_utilities: AppUtilityService, 50 | private feature_module_utilities: FeatureModuleBService 51 | ) { 52 | this.table_update_form = new FormGroup({ 53 | a: new FormControl('',[Validators.required]), 54 | b: new FormControl('',[]), 55 | c: new FormControl('',[]) 56 | }); 57 | } 58 | 59 | ngOnInit(): void { 60 | } 61 | 62 | addNewRow(){ 63 | // enabling the primary key fields 64 | this.global_utilities.toggleFormControls(this.table_update_form, this.table_config.primary_key_set, true); 65 | // to reset the entire form 66 | this.table_update_form.reset(); 67 | this.is_table_being_updated = true; 68 | this.is_new_row_being_added = true; 69 | } 70 | 71 | editRow(row: any){ 72 | this.existing_row_values = {...row}; 73 | // to reset the entire form 74 | this.table_update_form.reset(); 75 | // patch existing values in the form 76 | this.table_update_form.patchValue(row); 77 | // disabling the primary key fields 78 | this.global_utilities.toggleFormControls(this.table_update_form, this.table_config.primary_key_set, false); 79 | this.is_table_being_updated = true; 80 | this.is_new_row_being_added = false; 81 | } 82 | 83 | updateTableData(){ 84 | let updated_row_data = (this.is_new_row_being_added) ? {...this.table_update_form.value} : {...this.existing_row_values, ...this.table_update_form.value}; 85 | 86 | this.update_table_data_sub = this.feature_module_utilities.updateTableData(updated_row_data, this.is_new_row_being_added).subscribe( 87 | (table_data)=>{ 88 | //close the drawer and reset the update form 89 | this.is_table_being_updated = false; 90 | this.table_update_form.reset(); 91 | //update the table with latest values 92 | this.table_config.table_data_changer.next({ 93 | data: table_data, 94 | highlight: updated_row_data 95 | }); 96 | }, 97 | (error)=>{ 98 | this.global_utilities.showSnackbar(); 99 | } 100 | ); 101 | } 102 | 103 | ngOnDestroy(): void { 104 | this.global_utilities.unsubscribeAll([ 105 | this.update_table_data_sub 106 | ]); 107 | } 108 | 109 | 110 | } 111 | 112 | const DUMMY_TABLE_DATA: any[]= [ 113 | { a: 'Dummy1', b: 'Data String 1', c: 21}, 114 | { a: 'Dummy2', b: 'Data String 2', c: 22}, 115 | { a: 'Dummy3', b: 'Data String 3', c: 23}, 116 | { a: 'Dummy4', b: 'Data String 4', c: 24}, 117 | { a: 'Dummy5', b: 'Data String 5', c: 25}, 118 | { a: 'Dummy6', b: 'Data String 6', c: 26}, 119 | { a: 'Dummy7', b: 'Data String 7', c: 27}, 120 | { a: 'Dummy8', b: 'Data String 8', c: 28}, 121 | { a: 'Dummy9', b: 'Data String 9', c: 29}, 122 | { a: 'Dummy10', b: 'Data String 10', c: 30}, 123 | { a: 'Dummy11', b: 'Data String 11', c: 31}, 124 | { a: 'Dummy12', b: 'Data String 12', c: 32}, 125 | { a: 'Dummy13', b: 'Data String 13', c: 33}, 126 | { a: 'Dummy14', b: 'Data String 14', c: 34}, 127 | { a: 'Dummy15', b: 'Data String 15', c: 35}, 128 | { a: 'Dummy16', b: 'Data String 16', c: 36}, 129 | { a: 'Dummy17', b: 'Data String 17', c: 37}, 130 | { a: 'Dummy18', b: 'Data String 18', c: 38}, 131 | { a: 'Dummy19', b: 'Data String 19', c: 39}, 132 | { a: 'Dummy20', b: 'Data String 20', c: 40}, 133 | ]; 134 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/page-b8/page-b8.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Blog Posts

4 |
5 |

6 | Did you write the book of love and do you have faith in God above if the 7 | Bible tells you so? Now, do you believe in rock 'n' roll? Can music save 8 | your mortal soul? And can you teach me how to dance real slow? Well, I know 9 | that you're in love with him 'cause I saw you dancin' in the gym. You both 10 | kicked off your shoes. Man, I dig those rhythm and blues. I was a lonely 11 | teenage bronckin' buck with a pink carnation and a pickup truck but I knew I 12 | was out of luck. The day the music died. 13 |

14 | 80 |
81 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/page-b8/page-b8.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/app/modules/feature-module-b/page-b8/page-b8.component.scss -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/page-b8/page-b8.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PageB8Component } from './page-b8.component'; 4 | 5 | describe('PageB8Component', () => { 6 | let component: PageB8Component; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ PageB8Component ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PageB8Component); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/modules/feature-module-b/page-b8/page-b8.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-page-b8', 5 | templateUrl: './page-b8.component.html', 6 | styleUrls: ['./page-b8.component.scss'] 7 | }) 8 | export class PageB8Component implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/.gitkeep -------------------------------------------------------------------------------- /src/assets/JSONs/file_download.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/JSONs/file_download.json -------------------------------------------------------------------------------- /src/assets/JSONs/file_upload.json: -------------------------------------------------------------------------------- 1 | { 2 | "responseCode" : 200, 3 | "uploadStatus" : "success" 4 | } -------------------------------------------------------------------------------- /src/assets/JSONs/loginservice.json: -------------------------------------------------------------------------------- 1 | { 2 | "responseCode" : 200, 3 | "loggedInUser" : "dhyatterika" 4 | } -------------------------------------------------------------------------------- /src/assets/JSONs/table_row_add.json: -------------------------------------------------------------------------------- 1 | { 2 | "responseCode" : 200, 3 | "tableData" : [ 4 | { "a": "Dummy1", "b": "Data String 1", "c": 21}, 5 | { "a": "Dummy2", "b": "Data String 2", "c": 22}, 6 | { "a": "Dummy3", "b": "Data String 3", "c": 23}, 7 | { "a": "Dummy4", "b": "Data String 4", "c": 24}, 8 | { "a": "Dummy5", "b": "Data String 5", "c": 25}, 9 | { "a": "Dummy6", "b": "Data String 6", "c": 26}, 10 | { "a": "Dummy7", "b": "Data String 7", "c": 27}, 11 | { "a": "Dummy8", "b": "Data String 8", "c": 28}, 12 | { "a": "Dummy9", "b": "Data String 9", "c": 29}, 13 | { "a": "Dummy10", "b": "Data String 10", "c": 30}, 14 | { "a": "Dummy11", "b": "Data String 11", "c": 31}, 15 | { "a": "Dummy12", "b": "Data String 12", "c": 32}, 16 | { "a": "Dummy13", "b": "Data String 13", "c": 33}, 17 | { "a": "Dummy14", "b": "Data String 14", "c": 34}, 18 | { "a": "Dummy15", "b": "Data String 15", "c": 35}, 19 | { "a": "Dummy16", "b": "Data String 16", "c": 36}, 20 | { "a": "Dummy17", "b": "Data String 17", "c": 37}, 21 | { "a": "Dummy18", "b": "Data String 18", "c": 38}, 22 | { "a": "Dummy19", "b": "Data String 19", "c": 39}, 23 | { "a": "Dummy99", "b": "New String 99", "c": 99}, 24 | { "a": "Dummy20", "b": "Data String 20", "c": 40} 25 | ] 26 | } -------------------------------------------------------------------------------- /src/assets/JSONs/table_row_edit.json: -------------------------------------------------------------------------------- 1 | { 2 | "responseCode" : 200, 3 | "tableData" : [ 4 | { "a": "Dummy1", "b": "Data String 1", "c": 21}, 5 | { "a": "Dummy2", "b": "Data String 2", "c": 22}, 6 | { "a": "Dummy3", "b": "Data String 3", "c": 23}, 7 | { "a": "Dummy4", "b": "Edited String 4", "c": 24}, 8 | { "a": "Dummy5", "b": "Data String 5", "c": 25}, 9 | { "a": "Dummy6", "b": "Data String 6", "c": 26}, 10 | { "a": "Dummy7", "b": "Data String 7", "c": 27}, 11 | { "a": "Dummy8", "b": "Data String 8", "c": 28}, 12 | { "a": "Dummy9", "b": "Data String 9", "c": 29}, 13 | { "a": "Dummy10", "b": "Data String 10", "c": 30}, 14 | { "a": "Dummy11", "b": "Data String 11", "c": 31}, 15 | { "a": "Dummy12", "b": "Data String 12", "c": 32}, 16 | { "a": "Dummy13", "b": "Data String 13", "c": 33}, 17 | { "a": "Dummy14", "b": "Data String 14", "c": 34}, 18 | { "a": "Dummy15", "b": "Data String 15", "c": 35}, 19 | { "a": "Dummy16", "b": "Data String 16", "c": 36}, 20 | { "a": "Dummy17", "b": "Data String 17", "c": 37}, 21 | { "a": "Dummy18", "b": "Data String 18", "c": 38}, 22 | { "a": "Dummy19", "b": "Data String 19", "c": 39}, 23 | { "a": "Dummy20", "b": "Data String 20", "c": 40} 24 | ] 25 | } -------------------------------------------------------------------------------- /src/assets/fonts/Roboto-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/Roboto-Bold.eot -------------------------------------------------------------------------------- /src/assets/fonts/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/Roboto-Bold.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Roboto-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/Roboto-Bold.woff -------------------------------------------------------------------------------- /src/assets/fonts/Roboto-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/Roboto-Bold.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/Roboto-Light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/Roboto-Light.eot -------------------------------------------------------------------------------- /src/assets/fonts/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/Roboto-Light.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Roboto-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/Roboto-Light.woff -------------------------------------------------------------------------------- /src/assets/fonts/Roboto-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/Roboto-Light.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/Roboto-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/Roboto-Regular.eot -------------------------------------------------------------------------------- /src/assets/fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Roboto-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/Roboto-Regular.woff -------------------------------------------------------------------------------- /src/assets/fonts/Roboto-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/Roboto-Regular.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/RobotoMono-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/RobotoMono-Regular.eot -------------------------------------------------------------------------------- /src/assets/fonts/RobotoMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/RobotoMono-Regular.ttf -------------------------------------------------------------------------------- /src/assets/fonts/RobotoMono-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/RobotoMono-Regular.woff -------------------------------------------------------------------------------- /src/assets/fonts/RobotoMono-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/RobotoMono-Regular.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/modhyobitto-icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/modhyobitto-icons.eot -------------------------------------------------------------------------------- /src/assets/fonts/modhyobitto-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/assets/fonts/modhyobitto-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/modhyobitto-icons.ttf -------------------------------------------------------------------------------- /src/assets/fonts/modhyobitto-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/fonts/modhyobitto-icons.woff -------------------------------------------------------------------------------- /src/assets/images/logo-nav@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/assets/images/logo-nav@2x.png -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | dummy_JSONs: true 4 | }; 5 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false, 7 | dummy_JSONs: true 8 | }; 9 | 10 | /* 11 | * For easier debugging in development mode, you can import the following file 12 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 13 | * 14 | * This import should be commented out in production mode because it will have a negative impact 15 | * on performance if an error is thrown. 16 | */ 17 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 18 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owrrpon/modhyobitto-angular/6261227d9d0058d723d1e1aa14ea9f14a5b28dd0/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Modhyobitto Angular 6 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /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 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /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/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** 22 | * IE11 requires the following for NgClass support on SVG elements 23 | */ 24 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 25 | 26 | /** 27 | * Web Animations `@angular/platform-browser/animations` 28 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 29 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 30 | */ 31 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 32 | 33 | /** 34 | * By default, zone.js will patch all possible macroTask and DomEvents 35 | * user can disable parts of macroTask/DomEvents patch by setting following flags 36 | * because those flags need to be set before `zone.js` being loaded, and webpack 37 | * will put import in the top of bundle, so user need to create a separate file 38 | * in this directory (for example: zone-flags.ts), and put the following flags 39 | * into that file, and then add the following code before importing zone.js. 40 | * import './zone-flags'; 41 | * 42 | * The flags allowed in zone-flags.ts are listed here. 43 | * 44 | * The following flags will work for all browsers. 45 | * 46 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 47 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 48 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 49 | * 50 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 51 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 52 | * 53 | * (window as any).__Zone_enable_cross_context_check = true; 54 | * 55 | */ 56 | 57 | /*************************************************************************************************** 58 | * Zone JS is required by default for Angular itself. 59 | */ 60 | import 'zone.js'; // Included with Angular CLI. 61 | 62 | 63 | /*************************************************************************************************** 64 | * APPLICATION IMPORTS 65 | */ 66 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | //importing variables 2 | @import 'styles/variables'; 3 | 4 | //importing font-faces 5 | @import 'styles/font_families'; 6 | 7 | //importing the good parts from Bootstrap 8 | //Dependencies 9 | @import '~bootstrap/scss/functions'; 10 | @import '~bootstrap/scss/variables'; 11 | @import '~bootstrap/scss/mixins'; 12 | //Grid 13 | @import "~bootstrap/scss/vendor/rfs"; 14 | @import "~bootstrap/scss/containers"; 15 | @import "~bootstrap/scss/grid"; 16 | //Reboot 17 | @import '~bootstrap/scss/reboot'; 18 | //Utilities 19 | @import '~bootstrap/scss/utilities'; 20 | @import '~bootstrap/scss/utilities/api'; 21 | 22 | //importing Angular Material theme 23 | @import 'styles/material_theme'; 24 | 25 | //importing icons 26 | @import 'styles/modhyobitto_icons'; 27 | 28 | //importing base element styles 29 | @import 'styles/base_elements'; 30 | 31 | //importing module specific styles 32 | @import 'styles/module_importer'; 33 | 34 | //importing common utility styles 35 | @import 'styles/global_styles'; 36 | -------------------------------------------------------------------------------- /src/styles/_base_elements.scss: -------------------------------------------------------------------------------- 1 | //This file will have the base styles written globally for the different HTML elements. E.g. headings, p, button, a. 2 | 3 | *{ 4 | box-sizing: border-box; 5 | &:active, 6 | :focus{ 7 | outline-offset: 3px; 8 | } 9 | &::-webkit-scrollbar{ 10 | width: 10px; 11 | } 12 | &::-webkit-scrollbar-thumb{ 13 | background: map-get($modhyobitto-colors, primary); 14 | } 15 | } 16 | 17 | :after, :before{ 18 | box-sizing: border-box; 19 | } 20 | 21 | html,body{ 22 | font-family: 'RobotoLight', sans-serif; 23 | font-size: 16px; 24 | color: map-get($modhyobitto-colors, default-text); 25 | } 26 | 27 | //headings 28 | h1, .h1{ 29 | font-size: 4.25rem; 30 | line-height: 110%; 31 | } 32 | h2, .h2{ 33 | font-size: 2.625rem; 34 | line-height: 110%; 35 | } 36 | h3, .h3{ 37 | font-size: 1.625rem; 38 | line-height: 125%; 39 | } 40 | h4, .h4{ 41 | font-size: 1.4rem; 42 | font-weight: lighter; 43 | } 44 | h5, .h5{ 45 | font-size: 1rem; 46 | line-height: 18px; 47 | } 48 | h6, .h6{ 49 | font-size: 1rem; 50 | line-height: 125%; 51 | } 52 | 53 | h1, h2, h3, h4, h5, h6{ 54 | font-family: 'Roboto', sans-serif; 55 | } 56 | 57 | a { 58 | color: map-get($modhyobitto-colors, primary); 59 | text-decoration: none; 60 | &:hover { 61 | color: map-get($modhyobitto-colors, primary-dark); 62 | text-decoration: underline; 63 | } 64 | } 65 | 66 | button { 67 | background: map-get($modhyobitto-colors, primary); 68 | border: none; 69 | box-shadow: none; 70 | color: white; 71 | font-family: 'Roboto', sans-serif; 72 | padding: 0 20px; 73 | text-transform: uppercase; 74 | &.primary-button, &.secondary-button{ 75 | min-width: 150px; 76 | } 77 | &.secondary-button{ 78 | background: map-get($modhyobitto-colors, primary-dark); 79 | } 80 | &:hover, &:focus{ 81 | outline: none; 82 | } 83 | &:not(.mat-focus-indicator){ 84 | height: 50px; 85 | &:hover, &:focus{ 86 | background: map-get($modhyobitto-colors, primary-light); 87 | color: map-get($modhyobitto-colors, default-text); 88 | outline: none; 89 | } 90 | &:disabled{ 91 | background: map-get($modhyobitto-colors, disabled-bg); 92 | color: map-get($modhyobitto-colors, disabled-text); 93 | } 94 | } 95 | .button-icon{ 96 | font-size: 2rem; 97 | margin-left: 10px; 98 | } 99 | 100 | } -------------------------------------------------------------------------------- /src/styles/_font_families.scss: -------------------------------------------------------------------------------- 1 | 2 | @font-face { 3 | font-family: 'Roboto'; 4 | src: url('../assets/fonts/Roboto-Regular.eot'); /* IE9 Compat Modes */ 5 | src: url('../assets/fonts/Roboto-Regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ 6 | url('../assets/fonts/Roboto-Regular.woff2') format('woff2'), /* Super Modern Browsers */ 7 | url('../assets/fonts/Roboto-Regular.woff') format('woff'), /* Pretty Modern Browsers */ 8 | url('../assets/fonts/Roboto-Regular.ttf') format('truetype'), /* Safari, Android, iOS */ 9 | url('../assets/fonts/Roboto-Regular.svg#svgFontName') format('svg'); /* Legacy iOS */ 10 | font-display: swap; 11 | } 12 | 13 | @font-face { 14 | font-family: 'RobotoLight'; 15 | src: url('../assets/fonts/Roboto-Light.eot'); /* IE9 Compat Modes */ 16 | src: url('../assets/fonts/Roboto-Light.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ 17 | url('../assets/fonts/Roboto-Light.woff2') format('woff2'), /* Super Modern Browsers */ 18 | url('../assets/fonts/Roboto-Light.woff') format('woff'), /* Pretty Modern Browsers */ 19 | url('../assets/fonts/Roboto-Light.ttf') format('truetype'), /* Safari, Android, iOS */ 20 | url('../assets/fonts/Roboto-Light.svg#svgFontName') format('svg'); /* Legacy iOS */ 21 | font-display: swap; 22 | } 23 | 24 | @font-face { 25 | font-family: 'RobotoBold'; 26 | src: url('../assets/fonts/Roboto-Bold.eot'); /* IE9 Compat Modes */ 27 | src: url('../assets/fonts/Roboto-Bold.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ 28 | url('../assets/fonts/Roboto-Bold.woff2') format('woff2'), /* Super Modern Browsers */ 29 | url('../assets/fonts/Roboto-Bold.woff') format('woff'), /* Pretty Modern Browsers */ 30 | url('../assets/fonts/Roboto-Bold.ttf') format('truetype'), /* Safari, Android, iOS */ 31 | url('../assets/fonts/Roboto-Bold.svg#svgFontName') format('svg'); /* Legacy iOS */ 32 | font-display: swap; 33 | } 34 | 35 | @font-face { 36 | font-family: 'RobotoMono'; 37 | src: url('../assets/fonts/RobotoMono-Regular.eot'); /* IE9 Compat Modes */ 38 | src: url('../assets/fonts/RobotoMono-Regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ 39 | url('../assets/fonts/RobotoMono-Regular.woff2') format('woff2'), /* Super Modern Browsers */ 40 | url('../assets/fonts/RobotoMono-Regular.woff') format('woff'), /* Pretty Modern Browsers */ 41 | url('../assets/fonts/RobotoMono-Regular.ttf') format('truetype'), /* Safari, Android, iOS */ 42 | url('../assets/fonts/RobotoMono-Regular.svg#svgFontName') format('svg'); /* Legacy iOS */ 43 | font-display: swap; 44 | } -------------------------------------------------------------------------------- /src/styles/_global_styles.scss: -------------------------------------------------------------------------------- 1 | //This file will have the styles written for application-specific utilities that are to be used across the application and not limited to a given feature module. 2 | 3 | .numeric-text{ 4 | font-family: 'RobotoMono', sans-serif; 5 | } 6 | 7 | .modhyobitto-icon{ 8 | font-size: 5rem; 9 | } 10 | 11 | .login-page{ 12 | height: 100vh; 13 | .login-page__banner{ 14 | color: white; 15 | background-color: map-get($modhyobitto-colors, primary); 16 | @include media-breakpoint-down(sm) { 17 | height: 180px; 18 | } 19 | h1{ 20 | font-family: 'RobotoBold', sans-serif; 21 | @include media-breakpoint-down(lg) { 22 | font-size: 3rem; 23 | } 24 | @include media-breakpoint-only(sm) { 25 | font-size: 1.8rem; 26 | } 27 | } 28 | .brand-logo{ 29 | @include media-breakpoint-down(lg) { 30 | width: 210px; 31 | } 32 | @include media-breakpoint-only(sm) { 33 | width: 150px; 34 | } 35 | } 36 | } 37 | .login-form-container{ 38 | display:flex; 39 | align-items: center; 40 | justify-content: center; 41 | @include media-breakpoint-down(sm) { 42 | height: calc(100vh - 180px); 43 | } 44 | .login-disclaimer{ 45 | color: map-get($modhyobitto-colors, primary-dark); 46 | font-size: 0.9rem; 47 | margin-bottom: 2rem; 48 | text-align: justify; 49 | width: 300px; 50 | } 51 | .login-form{ 52 | width: 300px; 53 | .login-form__footer{ 54 | margin: 25px 0; 55 | button{ 56 | width: 100%; 57 | } 58 | } 59 | } 60 | } 61 | } 62 | 63 | .secure-container__content{ 64 | padding: 220px 0 100px 0; 65 | @include media-breakpoint-down(md) { 66 | padding-top: 150px; 67 | } 68 | } 69 | 70 | .primary-header-container{ 71 | position: fixed; 72 | left: 0; 73 | right: 0; 74 | top: 0px; 75 | &.scrolled{ 76 | top: -70px; 77 | } 78 | 79 | transition-property: all; 80 | transition-duration: .5s; 81 | transition-timing-function: cubic-bezier(0, 1, 0.5, 1); 82 | z-index: 999; 83 | 84 | .primary-header, .primary-navigation{ 85 | padding: 0 15px; 86 | } 87 | 88 | .primary-header{ 89 | color: white; 90 | background-color: map-get($modhyobitto-colors, primary-dark); 91 | height: 70px; 92 | .brand-logo{ 93 | height: 40px; 94 | } 95 | .brand-name{ 96 | font-size: 2rem; 97 | font-family: 'RobotoBold', sans-serif; 98 | } 99 | } 100 | 101 | .primary-navigation{ 102 | background-color: map-get($modhyobitto-colors, primary-light); 103 | .mat-tab-nav-bar, .mat-tab-header{ 104 | border-bottom: none; 105 | } 106 | .mat-tab-links{ 107 | @include media-breakpoint-down(md) { 108 | justify-content: center; 109 | } 110 | } 111 | .mat-tab-link{ 112 | color: map-get($modhyobitto-colors, default-text); 113 | text-decoration: none; 114 | text-transform: uppercase; 115 | &.mat-tab-label-active, &:hover{ 116 | opacity: 1; 117 | } 118 | } 119 | .mat-ink-bar{ 120 | height: 4px; 121 | } 122 | } 123 | } 124 | 125 | %mat-action-button{ 126 | background: transparent; 127 | color: map-get($modhyobitto-colors, primary); 128 | font-family: 'RobotoBold', sans-serif; 129 | height: 35px; 130 | &:hover, &:focus{ 131 | background: map-get($modhyobitto-colors, subtle-bg); 132 | } 133 | } 134 | //banner 135 | .primary-banner{ 136 | background: white; 137 | position: fixed; 138 | left: 0; 139 | right: 0; 140 | top: 40px; 141 | transition: top 0.5s cubic-bezier(0, 1, 0.5, 1); 142 | z-index: 990; 143 | &.scrolled{ 144 | top: -30px; 145 | } 146 | .primary-banner__content{ 147 | display: flex; 148 | align-items: center; 149 | font-family: 'Roboto', sans-serif; 150 | font-size: 0.875rem; 151 | justify-content: center; 152 | min-height: 50px; 153 | opacity: 0; 154 | .primary-banner__graphic-text-wrapper, .primary-banner__action{ 155 | padding: 1rem; 156 | margin: 0 1rem; 157 | } 158 | .primary-banner__action{ 159 | button{ 160 | @extend %mat-action-button; 161 | } 162 | } 163 | } 164 | &.open{ 165 | top: 118px; 166 | &.scrolled{ 167 | top: 48px; 168 | } 169 | .primary-banner__content{ 170 | opacity: 1; 171 | } 172 | } 173 | } 174 | 175 | // Snack bar 176 | .modhyobitto-snackbar.mat-snack-bar-container{ 177 | border-radius: 0; 178 | .mat-simple-snackbar-action{ 179 | color: map-get($modhyobitto-colors, primary-light); 180 | button{ 181 | font-family: 'RobotoBold', sans-serif; 182 | } 183 | } 184 | } 185 | 186 | // Dialog 187 | .modhyobitto-dialog-container{ 188 | .mat-dialog-container{ 189 | border-radius: 0; 190 | } 191 | } 192 | .modhyobitto-dialog{ 193 | max-width: 500px; 194 | .mat-dialog-title{ 195 | border-bottom: 1px solid map-get($modhyobitto-colors, divider); 196 | color: map-get($modhyobitto-colors, primary-dark); 197 | font-family: 'Roboto', sans-serif; 198 | margin-bottom: 1rem; 199 | padding-bottom: 0.5rem; 200 | } 201 | .mat-dialog-content{ 202 | margin-bottom: 2rem; 203 | } 204 | .mat-dialog-actions{ 205 | justify-content: flex-end; 206 | button{ 207 | @extend %mat-action-button; 208 | } 209 | } 210 | } 211 | 212 | // Tooltip 213 | .mat-tooltip-panel{ 214 | .mat-tooltip{ 215 | border-radius: 0; 216 | } 217 | } 218 | 219 | .primary-footer{ 220 | background-color: map-get($modhyobitto-colors, primary-dark); 221 | color: white; 222 | font-size: 0.95rem; 223 | padding: 50px 0; 224 | .primary-footer__sitemap{ 225 | .section-link-container{ 226 | padding: 0 2rem; 227 | .section-header{ 228 | font-family: 'RobotoBold', sans-serif; 229 | text-transform: uppercase; 230 | } 231 | .section-links{ 232 | font-family: 'Roboto', sans-serif; 233 | list-style-type: none; 234 | margin-top: 1rem; 235 | padding: 0px; 236 | li{ 237 | margin-bottom: 10px; 238 | a{ 239 | color: white; 240 | &:hover{ 241 | color: map-get($modhyobitto-colors, primary-light); 242 | } 243 | } 244 | } 245 | } 246 | @include media-breakpoint-down(md) { 247 | text-align: center; 248 | } 249 | } 250 | } 251 | .primary-footer__legal{ 252 | margin-top: 75px; 253 | .primary-footer__legal-disclaimer{ 254 | border-top: 1px solid map-get($modhyobitto-colors, primary-light); 255 | p{ 256 | margin-top: 30px; 257 | text-align: justify; 258 | } 259 | } 260 | .primary-footer__legal-copyright{ 261 | margin-top: 3rem; 262 | } 263 | .brand-logo{ 264 | height: 30px; 265 | margin-right: 60px; 266 | } 267 | } 268 | } 269 | 270 | .loader-container{ 271 | background: white; 272 | position: fixed; 273 | top: 0; 274 | right: 0; 275 | left: 0; 276 | bottom: 0; 277 | display: flex; 278 | justify-content: center; 279 | align-items: center; 280 | flex-direction: column; 281 | opacity: 0.9; 282 | z-index: 1000; 283 | mat-spinner circle{ 284 | animation: mat-progress-spinner-stroke-rotate-100 4s cubic-bezier(.35,0,.25,1) infinite , color 4s ease-in-out infinite!important; 285 | stroke-linecap: round; 286 | } 287 | 288 | @keyframes color { 289 | 100%, 290 | 0% { 291 | stroke: map-get($modhyobitto-colors,primary); 292 | } 293 | 40% { 294 | stroke: map-get($modhyobitto-colors,primary-dark); 295 | } 296 | 66% { 297 | stroke: map-get($modhyobitto-colors,primary-light); 298 | } 299 | 80%, 300 | 90% { 301 | stroke: map-get($modhyobitto-colors,primary); 302 | } 303 | } 304 | .loader-container__text{ 305 | font-family: 'RobotoBold', sans-serif; 306 | font-size: 1.2rem; 307 | margin-top: 30px; 308 | } 309 | } 310 | 311 | 312 | 313 | .side-bar{ 314 | padding-right: 30px; 315 | padding-top: 2rem; 316 | .side-bar__heading{ 317 | color: map-get($modhyobitto-colors, primary-dark); 318 | font-size: 2rem; 319 | margin-bottom: 1rem; 320 | @include media-breakpoint-down(md) { 321 | display: flex; 322 | } 323 | } 324 | .side-bar__navigation{ 325 | .side-bar__navigation-links{ 326 | font-family: 'Roboto', sans-serif; 327 | list-style-type: none; 328 | padding:0; 329 | li{ 330 | padding-top: 8px; 331 | padding-bottom: 8px; 332 | border-top: solid 1px map-get($modhyobitto-colors, divider); 333 | &:last-of-type{ 334 | border-bottom: solid 1px map-get($modhyobitto-colors, divider); 335 | } 336 | } 337 | .side-bar__navigation-links--active{ 338 | color: map-get($modhyobitto-colors, primary-dark); 339 | cursor: default; 340 | font-family: 'Roboto', sans-serif; 341 | &:hover{ 342 | text-decoration: none; 343 | } 344 | } 345 | } 346 | } 347 | .side-bar__menu{ 348 | @extend %mat-action-button; 349 | color: map-get($modhyobitto-colors, primary); 350 | span{ 351 | font-size: 2rem; 352 | } 353 | &:hover, &:focus{ 354 | background: transparent; 355 | color: map-get($modhyobitto-colors, primary-dark); 356 | } 357 | @include media-breakpoint-up(md) { 358 | display: none; 359 | } 360 | } 361 | } 362 | .side-bar__menu-items{ 363 | &.mat-menu-panel{ 364 | border-radius: 0; 365 | } 366 | button{ 367 | color: map-get($modhyobitto-colors, primary); 368 | font-family: 'Roboto', sans-serif; 369 | text-transform: none; 370 | &.side-bar__menu-item--active{ 371 | background: map-get($modhyobitto-colors, subtle-bg); 372 | color: map-get($modhyobitto-colors, primary-dark); 373 | font-family: 'RobotoBold', sans-serif; 374 | } 375 | } 376 | } 377 | 378 | .page-content{ 379 | min-height: 400px; 380 | //dashboard 381 | &.dashboard{ 382 | @include media-breakpoint-down(md) { 383 | padding-top: 50px; 384 | } 385 | } 386 | .page-sub-section{ 387 | margin-bottom: 1.5rem; 388 | .page-sub-section__header{ 389 | color: map-get($modhyobitto-colors, primary-dark); 390 | font-family: 'Roboto', sans-serif; 391 | margin-bottom: 0.5rem; 392 | @include media-breakpoint-down(lg) { 393 | text-align: center; 394 | } 395 | } 396 | .page-sub-section__info{ 397 | margin-bottom: 0.5rem; 398 | .page-sub-section__description{ 399 | margin-bottom: 0; 400 | text-align: justify; 401 | @include media-breakpoint-only(sm) { 402 | padding-left: 15px; 403 | } 404 | @include media-breakpoint-up(lg) { 405 | padding-left: 15px; 406 | } 407 | } 408 | @include media-breakpoint-down(sm) { 409 | flex-direction: column; 410 | } 411 | @include media-breakpoint-only(md) { 412 | flex-direction: column; 413 | } 414 | } 415 | .page-sub-section__links{ 416 | list-style-type: none; 417 | padding-left: 1rem; 418 | @include media-breakpoint-down(lg) { 419 | text-align: center; 420 | } 421 | } 422 | } 423 | .page-content__header{ 424 | margin-bottom: 3rem; 425 | h1{ 426 | margin-bottom: 0; 427 | @include media-breakpoint-down(sm) { 428 | font-size: 3.75rem; 429 | } 430 | } 431 | } 432 | .page-content__description{ 433 | text-align: justify; 434 | } 435 | } 436 | 437 | //form field 438 | 439 | .modhyobitto-form-field{ 440 | mat-form-field{ 441 | width: 100%; 442 | &.mat-form-field-appearance-fill{ 443 | .mat-form-field-flex{ 444 | background-color: map-get($modhyobitto-colors, subtle-bg); 445 | border-radius: 0; 446 | border: 1px solid transparent; 447 | .mat-form-field-infix{ 448 | padding-left: 0.5em; 449 | padding-right: 0.5em; 450 | } 451 | } 452 | .mat-form-field-wrapper{ 453 | margin-bottom: 12px; 454 | } 455 | .mat-form-field-label{ 456 | left: 8px; 457 | } 458 | .mat-form-field-underline{ 459 | opacity: 0; 460 | } 461 | } 462 | &.mat-focused{ 463 | .mat-form-field-flex{ 464 | border: 1px solid map-get($modhyobitto-colors, primary); 465 | } 466 | &.mat-form-field-invalid{ 467 | .mat-form-field-flex{ 468 | border: 1px solid map-get($modhyobitto-colors, notification); 469 | } 470 | } 471 | } 472 | &, &.mat-focused{ 473 | .placeholder-required{ 474 | color: map-get($modhyobitto-colors, notification); 475 | } 476 | } 477 | } 478 | } 479 | .modhyobitto-checkbox{ 480 | ul{ 481 | list-style-type: none; 482 | margin-bottom: 0.5rem; 483 | } 484 | } 485 | .modhyobitto-radio{ 486 | .mat-radio-group{ 487 | margin-bottom: 0.5rem; 488 | } 489 | } 490 | .modhyobitto-checkbox, .modhyobitto-radio{ 491 | .placeholder-required{ 492 | color: map-get($modhyobitto-colors, notification); 493 | } 494 | .mat-error{ 495 | font-size:75%; 496 | } 497 | } 498 | 499 | .mat-select-panel-wrap{ 500 | .mat-select-panel{ 501 | border-radius: 0; 502 | } 503 | } 504 | 505 | .modhyobitto-file-uploader{ 506 | background-color: map-get($modhyobitto-colors, subtle-bg); 507 | border: 2px dashed map-get($modhyobitto-colors, primary); 508 | padding: 3rem; 509 | @include media-breakpoint-down(lg) { 510 | padding: 2rem; 511 | } 512 | @include media-breakpoint-down(sm) { 513 | padding: 1rem; 514 | } 515 | .files-for-upload{ 516 | margin-bottom: 3rem; 517 | .selected-file{ 518 | border-radius: 0; 519 | font-family: 'Roboto', sans-serif; 520 | &:not(:last-of-type){ 521 | margin-bottom: 1rem; 522 | } 523 | .mat-expansion-panel-header{ 524 | cursor: default; 525 | height: auto; 526 | padding: 0; 527 | &[aria-disabled=true]{ 528 | color: inherit; 529 | } 530 | .selected-file__header{ 531 | display: flex; 532 | align-items: center; 533 | justify-content: space-between; 534 | .selected-file__name{ 535 | color: map-get($modhyobitto-colors, primary-dark); 536 | overflow: hidden; 537 | padding: 0 1.5rem; 538 | text-overflow: ellipsis; 539 | white-space: nowrap; 540 | } 541 | .selected-file__actions{ 542 | display: flex; 543 | justify-content: flex-end; 544 | button{ 545 | display: flex; 546 | align-items: center; 547 | min-width: 0; 548 | padding: 0 15px; 549 | } 550 | } 551 | } 552 | &.mat-expanded{ 553 | .selected-file__header{ 554 | border-bottom: solid 1px map-get($modhyobitto-colors, divider); 555 | } 556 | } 557 | .mat-content{ 558 | display: block; 559 | } 560 | 561 | } 562 | .mat-expansion-panel-body{ 563 | padding-top: 1rem; 564 | .selected-file__upload--error{ 565 | color: map-get($modhyobitto-colors, notification); 566 | } 567 | } 568 | 569 | 570 | } 571 | } 572 | .file-uploader__instructions{ 573 | color: map-get($modhyobitto-colors, primary); 574 | margin-bottom: 3rem; 575 | padding: 0 1rem; 576 | text-align: center; 577 | @include media-breakpoint-down(lg) { 578 | margin-bottom: 2rem; 579 | } 580 | @include media-breakpoint-down(sm) { 581 | margin-bottom: 1rem; 582 | } 583 | } 584 | .file-upload__options{ 585 | display: flex; 586 | justify-content: center; 587 | button{ 588 | &.all_file__upload, &.all_file__cancel{ 589 | display: flex; 590 | align-items: center; 591 | border-left: 2px solid map-get($modhyobitto-colors, subtle-bg); 592 | min-width: 0; 593 | padding: 0 15px; 594 | } 595 | } 596 | .file-upload__native-selection{ 597 | display: none; 598 | } 599 | } 600 | } 601 | 602 | .modhyobitto-table{ 603 | border: solid 1px map-get($modhyobitto-colors, primary); 604 | .modhyobitto-table__grid{ 605 | width: 100%; 606 | .mat-header-row{ 607 | background-color: map-get($modhyobitto-colors, primary); 608 | .mat-header-cell{ 609 | color: white; 610 | font-family: 'Roboto', sans-serif; 611 | font-size: 1rem; 612 | } 613 | } 614 | .highlighted-row{ 615 | animation-name: highlighted-row-pulse; 616 | animation-duration: 1s; 617 | animation-direction: alternate; 618 | animation-iteration-count: 4; 619 | 620 | @keyframes highlighted-row-pulse { 621 | 0% { 622 | background-color: transparent; 623 | } 624 | 100% { 625 | background-color: map-get($modhyobitto-colors, primary-light); 626 | } 627 | } 628 | } 629 | .mat-cell{ 630 | color: map-get($modhyobitto-colors, default-text); 631 | &.row-action-column{ 632 | padding: 0 8px 0 1.5rem; 633 | width: 72px; 634 | } 635 | } 636 | .numeric-col{ 637 | &.mat-cell, &.mat-header-cell{ 638 | text-align: right; 639 | padding-right: 1.5rem; 640 | } 641 | &.mat-cell{ 642 | font-family: 'RobotoMono', sans-serif; 643 | } 644 | } 645 | } 646 | .modhyobitto-table__add{ 647 | display: flex; 648 | justify-content: flex-end; 649 | padding: 10px 8px 0; 650 | } 651 | .modhyobitto-table__action-button{ 652 | background: transparent; 653 | border-radius: 50%; 654 | color: map-get($modhyobitto-colors, primary); 655 | height: 40px; 656 | padding: 0; 657 | width: 40px; 658 | display: flex; 659 | justify-content: center; 660 | align-items: center; 661 | &:focus{ 662 | background: map-get($modhyobitto-colors, disabled-bg); 663 | } 664 | &:hover{ 665 | background: transparent; 666 | } 667 | &:focus, &:hover{ 668 | color: map-get($modhyobitto-colors, primary); 669 | } 670 | } 671 | } 672 | .mat-paginator-container{ 673 | font-family: 'Roboto', sans-serif; 674 | .mat-paginator-page-size-label, .mat-select-trigger, .mat-paginator-range-label{ 675 | color: map-get($modhyobitto-colors, default-text); 676 | font-size: 14px; 677 | } 678 | .mat-paginator-range-actions{ 679 | button{ 680 | color: map-get($modhyobitto-colors, primary); 681 | } 682 | } 683 | } 684 | 685 | .modhyobitto-table-drawer-container{ 686 | mat-drawer{ 687 | .table-update{ 688 | padding: 1rem 2rem; 689 | .table-update__header{ 690 | h2{ 691 | border-bottom: 1px solid map-get($modhyobitto-colors, divider); 692 | color: map-get($modhyobitto-colors, primary-dark); 693 | font-family: 'Roboto', sans-serif; 694 | margin-bottom: 1rem; 695 | padding-bottom: 0.5rem; 696 | } 697 | margin-bottom: 2rem; 698 | } 699 | .table-update__footer{ 700 | margin: 1.5rem 0; 701 | @include media-breakpoint-down(sm) { 702 | margin: 1rem 0; 703 | } 704 | button{ 705 | width: 100%; 706 | } 707 | } 708 | } 709 | } 710 | } -------------------------------------------------------------------------------- /src/styles/_material_theme.scss: -------------------------------------------------------------------------------- 1 | // Custom Theming for Angular Material 2 | // For more information: https://material.angular.io/guide/theming 3 | @use '~@angular/material' as mat; 4 | // Plus imports for other components in your app. 5 | 6 | // Making the application typography over-ride the default Angular Material typography 7 | $modhyobitto-typography: mat.define-typography-config( 8 | $font-family: inherit 9 | ); 10 | 11 | // Include the common styles for Angular Material. We include this here so that you only 12 | // have to load a single css file for Angular Material in your app. 13 | // Be sure that you only ever include this mixin once! 14 | @include mat.core($modhyobitto-typography); 15 | 16 | // Define the palettes for your theme using the Material Design palettes available in palette.scss 17 | // (imported above). For each palette, you can optionally specify a default, lighter, and darker 18 | // hue. Available color palettes: https://material.io/design/color/ 19 | $modhyobitto-palette: ( 20 | 50: #f1f8e9, 21 | 100: #dcedc8, 22 | 200: #c5e1a5, 23 | 300: #aee571, 24 | 400: #9ccc65, 25 | 500: #8bc34a, 26 | 600: #7cb342, 27 | 700: #689f38, 28 | 800: #558b2f, 29 | 900: #4b830d, 30 | contrast: ( 31 | 50: black, 32 | 100: black, 33 | 200: black, 34 | 300: black, 35 | 400: black, 36 | 500: black, 37 | 600: black, 38 | 700: white, 39 | 800: white, 40 | 900: white 41 | ) 42 | ); 43 | 44 | $modhyobitto-warn-palette: ( 45 | 50: #fdeaee, 46 | 100: #fbcad2, 47 | 200: #ea959b, 48 | 300: #de6c74, 49 | 400: #e84853, 50 | 500: #ed323b, 51 | 600: #de2839, 52 | 700: #cc1d33, 53 | 800: #bf152c, 54 | 900: #b00020, 55 | contrast: ( 56 | 50: black, 57 | 100: black, 58 | 200: black, 59 | 300: black, 60 | 400: black, 61 | 500: black, 62 | 600: white, 63 | 700: white, 64 | 800: white, 65 | 900: white 66 | ) 67 | ); 68 | 69 | $modhyobitto-angular-primary: mat.define-palette($modhyobitto-palette, 600, 300, 900); 70 | $modhyobitto-angular-accent: mat.define-palette($modhyobitto-palette, 900, 300, 600); 71 | 72 | // The warn palette is optional (defaults to red). 73 | $modhyobitto-angular-warn: mat.define-palette($modhyobitto-warn-palette, 900); 74 | 75 | // Create the theme object. A theme consists of configurations for individual 76 | // theming systems such as "color" or "typography". 77 | $modhyobitto-angular-theme: mat.define-light-theme(( 78 | color: ( 79 | primary: $modhyobitto-angular-primary, 80 | accent: $modhyobitto-angular-accent, 81 | warn: $modhyobitto-angular-warn, 82 | ) 83 | )); 84 | 85 | // Include theme styles for core and each component used in your app. 86 | // Alternatively, you can import and @include the theme mixins for each component 87 | // that you are using. 88 | @include mat.all-component-themes($modhyobitto-angular-theme); 89 | -------------------------------------------------------------------------------- /src/styles/_modhyobitto_icons.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'modhyobitto-icons'; 3 | src: url('../assets/fonts/modhyobitto-icons.eot?uzso5b'); 4 | src: url('../assets/fonts/modhyobitto-icons.eot?uzso5b#iefix') format('embedded-opentype'), 5 | url('../assets/fonts/modhyobitto-icons.ttf?uzso5b') format('truetype'), 6 | url('../assets/fonts/modhyobitto-icons.woff?uzso5b') format('woff'), 7 | url('../assets/fonts/modhyobitto-icons.svg?uzso5b#modhyobitto-icons') format('svg'); 8 | font-weight: normal; 9 | font-style: normal; 10 | font-display: block; 11 | } 12 | 13 | .modhyobitto-icon { 14 | /* use !important to prevent issues with browser extensions that change fonts */ 15 | font-family: 'modhyobitto-icons' !important; 16 | speak: never; 17 | font-style: normal; 18 | font-weight: normal; 19 | font-variant: normal; 20 | text-transform: none; 21 | line-height: 1; 22 | 23 | /* Better Font Rendering =========== */ 24 | -webkit-font-smoothing: antialiased; 25 | -moz-osx-font-smoothing: grayscale; 26 | } 27 | 28 | .modhyobitto-address:before { 29 | content: "\e900"; 30 | } 31 | .modhyobitto-delivery:before { 32 | content: "\e901"; 33 | } 34 | .modhyobitto-express-mail:before { 35 | content: "\e902"; 36 | } 37 | .modhyobitto-post-office:before { 38 | content: "\e903"; 39 | } 40 | -------------------------------------------------------------------------------- /src/styles/_module_importer.scss: -------------------------------------------------------------------------------- 1 | //This file will be used to import all module-specific SCSS files mentioned in the /modules directory. 2 | 3 | @import 'modules/feature_module_a'; 4 | @import 'modules/feature_module_b'; -------------------------------------------------------------------------------- /src/styles/_variables.scss: -------------------------------------------------------------------------------- 1 | //This file will have the style variables that will be needed across the application. 2 | 3 | $modhyobitto-colors: ( 4 | primary: #7cb342, 5 | primary-light: #aee571, 6 | primary-dark: #4b830d, 7 | 8 | notification: #B00020, 9 | subtle-bg: #EEEEEE, 10 | default-text: #000000, 11 | 12 | disabled-text: rgb(0,0,0,0.26), 13 | disabled-bg: rgb(0,0,0,0.12), 14 | divider: rgb(0,0,0,0.12) 15 | ); 16 | 17 | -------------------------------------------------------------------------------- /src/styles/modules/_feature_module_a.scss: -------------------------------------------------------------------------------- 1 | //This file will have feature module specific styles that will not be used outside this particular module. 2 | 3 | .form-fields-demo{ 4 | .form-fields-demo__footer{ 5 | margin-top: 3rem; 6 | button{ 7 | margin-top: 2rem; 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/styles/modules/_feature_module_b.scss: -------------------------------------------------------------------------------- 1 | //This file will have feature module specific styles that will not be used outside this particular module. 2 | 3 | .blog-links{ 4 | list-style: none; 5 | margin-top: 2rem; 6 | li{ 7 | display: flex; 8 | align-items: flex-start; 9 | margin-bottom: 1rem; 10 | span{ 11 | color: map-get($modhyobitto-colors, primary); 12 | margin-right: 0.5rem; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /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/testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | keys(): string[]; 13 | (id: string): T; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting() 21 | ); 22 | // Then we find all the tests. 23 | const context = require.context('./', true, /\.spec\.ts$/); 24 | // And load the modules. 25 | context.keys().map(context); 26 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "noImplicitReturns": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "sourceMap": true, 12 | "declaration": false, 13 | "downlevelIteration": true, 14 | "experimentalDecorators": true, 15 | "moduleResolution": "node", 16 | "importHelpers": true, 17 | "target": "es2017", 18 | "module": "es2020", 19 | "lib": [ 20 | "es2018", 21 | "dom" 22 | ] 23 | }, 24 | "angularCompilerOptions": { 25 | "enableI18nLegacyMessageIdFormat": false, 26 | "strictInjectionParameters": true, 27 | "strictInputAccessModifiers": true, 28 | "strictTemplates": true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | --------------------------------------------------------------------------------