first commit

This commit is contained in:
Fuzi_fauzia 2024-04-19 12:53:45 +07:00
commit 71a3a661dc
1943 changed files with 246917 additions and 0 deletions

42
.gitignore vendored Normal file
View File

@ -0,0 +1,42 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db

108
README.md Normal file
View File

@ -0,0 +1,108 @@
# Modern Admin - Angular 15+ Bootstrap 5 Admin Dashboard Template
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.0.1
## Prerequisite Softwares
Min 2 GB free space on the drive
Node Js - Version 12+
Git 2+
npm install -g typescript
npm install -g @angular/cli
## Development server
Run `npm install` to install dependencies
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.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
## Firebase Deploy -- Only for production
node --max_old_space_size=8192 node_modules/@angular/cli/bin/ng build --output-hashing=all
node --max_old_space_size=8192 node_modules/@angular/cli/bin/ng s
firebase login
firebase projects:list
firebase use <instance name>
firebase deploy
firebase firestore:indexes
## Types of Layouts
Vertical Menu Template
Semi Dark Vertical Menu Template
Dark Nav Vertical Menu Template
Light Vertical Menu Template
Vertical Modern Menu Template
Vertical Overlay Menu Template
Horizontal Menu Template
Full Width Horizontal Menu Template
## Create New Module and Module
# Add Module
ng g m components
cd .\src\app\components\
# Add component
ng g c <componentname>
add new menu in menu setting
add new route in module and refernce to new <componentname>
copy html to component html
# c9 usage
cd modern-admin-angular
ng s --host 0.0.0.0 --port 8080 --disable-host-check
https://modern-admin-joshijimit.c9users.io:8080/
# Git commands
git pull origin wip_v1
git push origin ui-dev-branch
# Angular 8 Migrate
git checkout angular8
git pull origin angular8
(likely to conflict with package lock file, needs to keep the existing file and avoid incoming changes.
onece merge conflict resolved with other files if any, run npm install which updates the lock file.)
git add .
git commit -m "latest pull in v8"
git push origin angular8
known change in Angular 8
ViewChild should have second argument.
@ViewChild('labelImport', { static: true })
# CI - Gitlab
Auto deploy On merge to master branch
# Disable experimentalDecorators warning
https://ihatetomatoes.net/how-to-remove-experimentaldecorators-warning-in-vscode/
# Open issue in Angular 10
https://github.com/mattlewis92/angular-calendar/issues/1283
## Flickering issue
Remove all occurences of below text from index.html generated in dist folder
media="print" onload="this.media='all'"

164
angular.json Normal file
View File

@ -0,0 +1,164 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"modern-admin": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"prefix": "app",
"schematics": {},
"architect": {
"build": {
"assets": [
{
"glob": "**/*.@(svg|png|gif)",
"input": "./node_modules/photoswipe/src/css/default-skin",
"output": "/assets/media"
}
],
"builder": "@angular-devkit/build-angular:browser",
"options": {
"aot": true,
"outputPath": "dist",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css",
"node_modules/chartist/dist/chartist.css",
"node_modules/angular-calendar/css/angular-calendar.css",
"node_modules/flatpickr/dist/flatpickr.min.css",
"node_modules/ngx-ui-switch/ui-switch.component.css",
"node_modules/chartist-plugin-tooltips/dist/chartist-plugin-tooltip.css",
"node_modules/@swimlane/ngx-datatable/themes/bootstrap.css",
"src/assets/sass/main.scss",
"src/assets/jkanban/jkanban.min.css",
"node_modules/ngx-toastr/toastr.css",
"node_modules/photoswipe/dist/photoswipe.css",
"node_modules/photoswipe/dist/default-skin/default-skin.css"
],
"scripts": [
"node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js",
"node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"
],
"vendorChunk": true,
"extractLicenses": false,
"buildOptimizer": false,
"sourceMap": true,
"optimization": false,
"namedChunks": true
},
"configurations": {
"production": {
"budgets": [
{
"type": "anyComponentStyle",
"maximumWarning": "6kb"
}
],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"serviceWorker": false
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "modern-admin:build"
},
"configurations": {
"production": {
"browserTarget": "modern-admin:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "modern-admin:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json",
"karmaConfig": "src/karma.conf.js",
"styles": [
"src/styles.css"
],
"scripts": [],
"assets": [
"src/favicon.ico",
"src/assets"
]
}
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"eslintConfig": ".eslintrc.json",
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
}
}
}
},
"modern-admin-e2e": {
"root": "e2e/",
"projectType": "application",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "modern-admin:serve"
},
"configurations": {
"production": {
"devServerTarget": "modern-admin:serve:production"
}
}
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"eslintConfig": ".eslintrc.json",
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
}
}
}
}
},
"defaultProject": "modern-admin",
"cli": {
"analytics": false,
"defaultCollection": "@angular-eslint/schematics"
}
}

7
changelog.md Normal file
View File

@ -0,0 +1,7 @@
# Modern Admin - Angular 11+ Bootstrap 5 Admin Dashboard Template
V1.2 : [12-06-2019] : Added live chat functionality
V1.1 : [11-07-2019] : Added configuration to hide header icons
Added ngx-toastr in TODO application.
Added fully functional CRUD Firebase API integration for TODO App.
V1.0 : [10-12-2019] : Initial Release

28
e2e/protractor.conf.js Normal file
View File

@ -0,0 +1,28 @@
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./src/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.e2e.json')
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};

14
e2e/src/app.e2e-spec.ts Normal file
View File

@ -0,0 +1,14 @@
import { AppPage } from './app.po';
describe('workspace-project App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('Welcome to modern-admin!');
});
});

11
e2e/src/app.po.ts Normal file
View File

@ -0,0 +1,11 @@
import { browser, by, element } from 'protractor';
export class AppPage {
navigateTo() {
return browser.get('/');
}
getParagraphText() {
return element(by.css('app-root h1')).getText();
}
}

14
e2e/tsconfig.e2e.json Normal file
View File

@ -0,0 +1,14 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"experimentalDecorators": true,
"outDir": "../out-tsc/app",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}

21
e2e/tsconfig.json Normal file
View File

@ -0,0 +1,21 @@
/*
This is a "Solution Style" tsconfig.json file, and is used by editors and TypeScripts language server to improve development experience.
It is not intended to be used to perform a compilation.
To learn more about this file see: https://angular.io/config/solution-tsconfig.
*/
{
"files": [],
"references": [
{
"path": "./src/tsconfig.app.json"
},
{
"path": "./src/tsconfig.spec.json"
},
{
"path": "./e2e/tsconfig.e2e.json"
}
]
}

31
firebase.json Normal file
View File

@ -0,0 +1,31 @@
{
"hosting": {
"public": "dist",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
],
"headers": [
{
"source": "/**",
"headers": [
{
"key": "Cache-Control",
"value": "no-cache, no-store, must-revalidate"
}
]
}
]
},
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
}
}

72
firestore.indexes.json Normal file
View File

@ -0,0 +1,72 @@
{
"indexes": [
{
"collectionGroup": "todo",
"queryScope": "COLLECTION",
"fields": [
{
"fieldPath": "uid",
"order": "ASCENDING"
},
{
"fieldPath": "createdDate",
"order": "DESCENDING"
}
]
},
{
"collectionGroup": "TODO",
"queryScope": "COLLECTION",
"fields": [
{
"fieldPath": "uid",
"order": "ASCENDING"
},
{
"fieldPath": "createdDate",
"order": "DESCENDING"
}
]
},
{
"collectionGroup": "todo",
"queryScope": "COLLECTION",
"fields": [
{
"fieldPath": "uid",
"order": "ASCENDING"
},
{
"fieldPath": "createdDate",
"order": "DESCENDING"
}
]
},
{
"collectionGroup": "todo",
"queryScope": "COLLECTION",
"fields": [
{
"fieldPath": "assignedTo.uid",
"order": "ASCENDING"
},
{
"fieldPath": "createdDate",
"order": "DESCENDING"
}
]
}
],
"fieldOverrides": [
{
"collectionGroup": "TODO",
"fieldPath": "createdDate",
"indexes": [
{
"order": "DESCENDING",
"queryScope": "COLLECTION"
}
]
}
]
}

52
firestore.rules Normal file
View File

@ -0,0 +1,52 @@
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// A read rule can be divided into get and list rules
match /todo/{todo} {
// Applies to single document read requests
allow get: if request.auth.uid == resource.data.uid;
// Applies to queries and collection read requests
allow list;
}
// A write rule can be divided into create, update, and delete rules
match /todo/{todo} {
// Applies to writes to nonexistent documents
allow create;
// Applies to writes to existing documents
allow update;
// Applies to delete operations
allow delete;
}
// A read rule can be divided into get and list rules
match /users/ {users} {
// Applies to single document read requests
allow get;
// Applies to queries and collection read requests
allow list;
// Applies to writes to nonexistent documents
allow create;
}
// A read rule can be divided into get and list rules
match /chatroom/ {chatroom} {
// Applies to single document read requests
allow get;
// Applies to queries and collection read requests
allow list;
// Applies to writes to nonexistent documents
allow create;
// Applies to writes to existing documents
allow update;
}
}
}

9
ngcc.config.js Normal file
View File

@ -0,0 +1,9 @@
module.exports = {
packages: {
'angular2-text-mask': {
ignorableDeepImportMatchers: [
/text-mask-core\//,
]
},
},
};

33447
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

139
package.json Normal file
View File

@ -0,0 +1,139 @@
{
"name": "modern-admin-angular",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"ngcc": "ngcc --properties es2015 browser main module --async false --first-only",
"postinstall": "npm run ngcc",
"preinstall": "npx npm-force-resolutions",
"pwa": "ng build --prod && sw-precache --root=dist --config=precache-config.js"
},
"private": true,
"dependencies": {
"@angular/animations": "^15.0.4",
"@angular/cdk": "^15.0.4",
"@angular/common": "^15.0.4",
"@angular/compiler": "^15.0.4",
"@angular/core": "^15.0.4",
"@angular/fire": "^7.5.0",
"@angular/forms": "^15.0.4",
"@angular/localize": "^15.0.4",
"@angular/platform-browser": "^15.0.4",
"@angular/platform-browser-dynamic": "^15.0.4",
"@angular/router": "^15.0.4",
"@cds/core": "^6.2.3",
"@fnxone/ngx-photoswipe": "^1.0.11",
"@fullcalendar/angular": "^6.0.2",
"@ng-bootstrap/ng-bootstrap": "^14.0.0",
"@ng-select/ng-select": "^10.0.1",
"@ngx-loading-bar/core": "^6.0.2",
"@ngx-loading-bar/router": "^6.0.2",
"@ngx-translate/core": "^14.0.0",
"@popperjs/core": "^2.11.6",
"@trafficguard/device-detector-js": "^2.2.1-3.13.0",
"@types/google.maps": "^3.51.0",
"@webcomponents/webcomponentsjs": "^2.7.0",
"ajv-keywords": "^5.1.0",
"angular-archwizard": "^7.0.0",
"angular-calendar": "^0.31.0",
"angularx-flatpickr": "^7.0.0",
"autolinker": "^4.0.0",
"bootstrap": "^5.2.3",
"chart.js": "^4.1.1",
"chartist": "^0.11.4",
"chartist-plugin-tooltips": "0.0.17",
"clone": "^2.1.2",
"core-js": "^3.27.1",
"css-select": "^5.1.0",
"date-fns": "^2.28.0",
"deep-equal": "^2.0.5",
"echarts": "^5.4.1",
"eventemitter3": "^5.0.0",
"file-saver": "^2.0.5",
"flatpickr": "^4.6.13",
"google-libphonenumber": "^3.2.31",
"html2canvas": "^1.0.0-rc.7",
"icheck": "^1.0.2",
"js-datepicker": "^5.18.2",
"jspdf": "^2.5.1",
"jspdf-autotable": "^3.5.28",
"lodash-es": "^4.17.21",
"ng-chartist": "^4.1.0",
"ng-multiselect-dropdown": "^0.3.9",
"ngx-countdown": "^15.0.0",
"ngx-drag-and-drop-lists": "^1.3.3",
"ngx-dropzone": "^3.1.0",
"ngx-echarts": "^15.0.1",
"ngx-google-places-autocomplete": "^2.0.5",
"ngx-image-cropper": "^6.3.2",
"ngx-masonry": "^14.0.1",
"ngx-perfect-scrollbar": "^10.1.1",
"ngx-quill": "^20.0.1",
"ngx-toastr": "^16.0.1",
"ngx-ui-switch": "^14.0.3",
"npm-force-resolutions": "0.0.10",
"photoswipe": "^4.1.3",
"pug": "^3.0.2",
"quill": "^1.3.7",
"quill-delta": "^5.0.0",
"quill-mention": "^3.1.0",
"rxjs": "^7.5.5",
"sass": "^1.57.1",
"save": "^2.9.0",
"tree-ngx": "^4.3.0",
"tslib": "^2.4.1",
"util": "^0.12.5",
"uuid": "^9.0.0",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@angular-devkit/build-angular": "^15.0.4",
"@angular-devkit/build-webpack": "^0.1500.4",
"@angular-eslint/builder": "15.1.0",
"@angular-eslint/eslint-plugin": "15.1.0",
"@angular-eslint/eslint-plugin-template": "15.1.0",
"@angular-eslint/schematics": "15.1.0",
"@angular-eslint/template-parser": "15.1.0",
"@angular/cli": "^15.0.4",
"@angular/compiler-cli": "^15.0.4",
"@angular/language-service": "^15.0.4",
"@swimlane/ngx-datatable": "20.1.0",
"@types/chartist": "^0.9.38",
"@types/echarts": "^4.9.15",
"@types/jasmine": "^4.3.1",
"@types/jasminewd2": "^2.0.8",
"@types/jspdf": "^2.0.0",
"@types/node": "^18.11.18",
"@typescript-eslint/eslint-plugin": "5.48.0",
"@typescript-eslint/parser": "5.48.0",
"eslint": "^8.30.0",
"firebase": "^9.15.0",
"firebaseui": "^6.0.2",
"jasmine-core": "~4.5.0",
"jasmine-spec-reporter": "~7.0.0",
"karma": "^6.4.1",
"karma-chrome-launcher": "^3.1.1",
"karma-coverage-istanbul-reporter": "^3.0.3",
"karma-jasmine": "^5.1.0",
"karma-jasmine-html-reporter": "^2.0.0",
"ng-block-ui": "^3.0.2",
"ng2-charts": "^4.1.1",
"ngx-clipboard": "^15.1.0",
"ngx-custom-validators": "^11.0.0",
"ngx-spinner": "^15.0.1",
"postcss": "^8.4.20",
"resize-observer-polyfill": "^1.5.1",
"saas": "^1.0.0",
"ts-node": "~10.9.1",
"typescript": "^4.8.4",
"zone.js": "~0.12.0"
},
"peerDependencies": {
"postcss": "^8.3.5"
}
}

11
src/.browserslistrc Normal file
View File

@ -0,0 +1,11 @@
# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
#
# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11

View File

@ -0,0 +1,12 @@
import { TestBed } from '@angular/core/testing';
import { ChatService } from './chat.service';
describe('ChatService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: ChatService = TestBed.get(ChatService);
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,45 @@
import { Injectable } from '@angular/core';
import { AngularFirestore } from '@angular/fire/compat/firestore';
import { Chats } from 'src/app/content/applications/chat/chats';
import { Observable } from 'rxjs';
import { Timestamp, FieldValue, arrayUnion } from "firebase/firestore";
import { map } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class ChatService {
constructor(private afs: AngularFirestore) { }
getChats() {
return this.afs.collection('chatroom').snapshotChanges();
}
createChatRoom(data) {
return this.afs.collection('chatroom').add(data);
}
showChat(id): Observable<Chats> {
const chat = this.afs.doc<Chats>('chatroom/' + id);
return chat.snapshotChanges()
.pipe(
map(changes => {
const data = changes.payload.data() as Chats;
const chatId = changes.payload.id;
return { chatId, ...data };
}));
}
sendMessage(chatId, data) {
return this.afs.collection('chatroom').doc(chatId).update({
chatHistory: arrayUnion(data)
});
}
updateChatStatus (chatId, history) {
return this.afs.collection('chatroom').doc(chatId).update({
chatHistory: history
});
}
}

View File

@ -0,0 +1,12 @@
import { TestBed } from '@angular/core/testing';
import { TodoService } from './todo.service';
describe('TodoService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: TodoService = TestBed.get(TodoService);
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,53 @@
import { Injectable } from '@angular/core';
import { AngularFirestore } from '@angular/fire/compat/firestore';
import firebase from 'firebase/compat/app';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class TodoService {
formData;
loggedInUser = JSON.parse(localStorage.getItem('currentUser'));
ref = firebase.firestore().collection('todo');
constructor(private firestore: AngularFirestore) {
}
getTODOS(userId) {
return this.firestore.collection('todo', ref => ref.orderBy('createdDate', 'desc')
.where('uid', '==', userId)).snapshotChanges();
}
getAssignedTODOS(userId) {
return this.firestore.collection('todo', ref => ref.orderBy('createdDate', 'desc')
.where('assignedTo.uid', '==', userId)).snapshotChanges();
}
createTodo(todo): Observable<any> {
return new Observable((observer) => {
this.ref.add(todo).then((doc) => {
observer.next({
data: doc
});
});
});
}
sendMessage(todoId, data) {
return this.firestore.collection('todo').doc(todoId).update({
todoComments: data
});
}
updateTODO(id: string, data): Observable<any> {
return new Observable((observer) => {
this.ref.doc(id).set(data).then(() => {
observer.next();
});
});
}
deleteTodo(id: string): Promise<void> {
return this.ref.doc(id).delete();
}
}

View File

@ -0,0 +1,12 @@
import { TestBed } from '@angular/core/testing';
import { UserService } from './user.service';
describe('UserService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: UserService = TestBed.get(UserService);
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,27 @@
import { Injectable } from '@angular/core';
import { AngularFirestore } from '@angular/fire/compat/firestore';
import firebase from 'firebase/compat/app';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class UserService {
ref = firebase.firestore().collection('users');
constructor(private firestore: AngularFirestore) {
}
getUsers() {
return this.firestore.collection('users').snapshotChanges();
}
getCurrentUser(userId): Observable<any> {
return this.firestore.collection('users', ref => ref.where('uid', '==', userId)).snapshotChanges();
}
createUser(user) {
return this.ref.add(user);
}
}

View File

@ -0,0 +1,30 @@
import {
Directive,
AfterViewInit,
OnDestroy,
ElementRef,
OnInit,
Input,
HostBinding
} from '@angular/core';
interface CardOptions {
enableSticky?: boolean;
headOverlay?: boolean;
headLarge?: boolean;
class?: string[];
}
@Directive({
selector: '[mCard]'
})
export class CardDirective {
card: any;
@Input() options: CardOptions;
@HostBinding('class') class: any;
constructor(private el: ElementRef) {
this.class = this.el.nativeElement.classList;
}
}

View File

@ -0,0 +1,23 @@
import { Directive, Input, HostBinding } from '@angular/core'
/* eslint-disable @angular-eslint/no-host-metadata-property */
/* eslint-disable @angular-eslint/directive-selector */
@Directive({
selector: 'img[default]',
host: {
'(error)': 'updateUrl()',
'(load)': 'load()',
'[src]': 'src'
}
})
export class ImagePreloadDirective {
@Input() src: string;
@Input() default: string;
@HostBinding('class') className;
updateUrl() {
this.src = this.default;
}
load() {
this.className = 'image-loaded';
}
}

View File

@ -0,0 +1,64 @@
import { Directive, ElementRef, Input, HostListener, AfterViewInit } from '@angular/core';
/* eslint-disable @angular-eslint/directive-selector */
@Directive({
selector: '[matchHeight]'
})
export class MatchHeightDirective implements AfterViewInit {
// class name to match height
@Input()
matchHeight: string;
constructor(private el: ElementRef) {}
ngAfterViewInit() {
// call our matchHeight function here
setTimeout(() => {
this.matchHeights(this.el.nativeElement, this.matchHeight);
}, 700);
}
matchHeights(parent: HTMLElement, className: string) {
if (!parent) {
return;
}
// step 1: find all the child elements with the selected class name
const children = parent.getElementsByClassName(className);
if (!children) {
return;
}
// Match hight - fix --- comment below code
Array.from(children).forEach((x: HTMLElement) => {
x.style.height = 'initial';
});
// step 2a: get all the child elements heights
const itemHeights = Array.from(children).map(
x => x.getBoundingClientRect().height
);
// step 2b: find out the tallest
const maxHeight = itemHeights.reduce((prev, curr) => {
return curr > prev ? curr : prev;
}, 0);
// step 3: update all the child elements to the tallest height
if (window.innerWidth > 1200) {
Array.from(children).forEach(
(x: HTMLElement) => (x.style.height = `${maxHeight}px`)
);
} else if (window.innerWidth < 1199) {
Array.from(children).forEach(
(x: HTMLElement) => (x.style.height = `initial`)
);
}
}
@HostListener('window:resize')
onResize() {
// call our matchHeight function here
this.matchHeights(this.el.nativeElement, this.matchHeight);
}
}

View File

@ -0,0 +1,33 @@
import { Directive, EventEmitter, Input, Output } from '@angular/core';
export type SortDirection = 'asc' | 'desc' | '';
const rotate: { [key: string]: SortDirection } = {
asc: 'desc',
desc: '',
'': 'asc'
};
export interface SortEvent {
column: string;
direction: SortDirection;
}
/* eslint-disable @angular-eslint/directive-selector */
/* eslint-disable @angular-eslint/no-host-metadata-property */
/* eslint-disable @angular-eslint/directive-class-suffix */
@Directive({
selector: 'th[sortable]',
host: {
'[class.asc]': 'direction === "asc"',
'[class.desc]': 'direction === "desc"',
'(click)': 'rotate()'
}
})
export class NgbdSortableHeader {
@Input() sortable: string;
@Input() direction: SortDirection = '';
@Output() sort = new EventEmitter<SortEvent>();
rotate() {
this.direction = rotate[this.direction];
this.sort.emit({ column: this.sortable, direction: this.direction });
}
}

View File

@ -0,0 +1,20 @@
import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AuthService } from '../_services/auth.service';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private router: Router) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (localStorage.getItem('currentUser')) {
// Logged in so return true
return true;
}
// Not logged in so redirect to login page with the return url
this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
return false;
}
}

View File

@ -0,0 +1,4 @@
<div *ngIf !="message" [ngClass]="{ 'alert': message, 'alert-success': message.type === 'success',
'alert-danger': message.type === 'error' }">
{{message.text}}
</div>

View File

@ -0,0 +1,25 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
import { AlertService } from '../_services/alert.service';
@Component({
selector: 'app-alert',
templateUrl: 'alert.component.html'
})
export class AlertComponent implements OnInit, OnDestroy {
private subscription: Subscription;
message: any;
constructor(private alertService: AlertService) {}
ngOnInit() {
this.subscription = this.alertService.getMessage().subscribe(message => {
this.message = message;
});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}

View File

@ -0,0 +1,14 @@
export class AppConstants {
public static MOBILE_RESPONSIVE_WIDTH = 992;
public static MOBILE_RESPONSIVE_WIDTH_HORIZONTAL = 768;
public static NAVIGATION_TYPE_COLLAPSIBLE = 'menu-collapsible';
public static NAVIGATION_TYPE_ACCORDATION = 'menu-accordation';
public static LAYOUT_STYLE_HORIZONTAL = 'horizontal';
public static LAYOUT_STYLE_VERTICAL = 'vertical';
public static fireRefreshEventOnWindow = function() {
const evt = document.createEvent('HTMLEvents');
evt.initEvent('resize', true, false);
window.dispatchEvent(evt);
};
}

View File

@ -0,0 +1,95 @@
export function init(Survey: any) {
var widget = {
//the widget name. It should be unique and written in lowcase.
name: "textwithbutton",
//the widget title. It is how it will appear on the toolbox of the SurveyJS Editor/Builder
title: "Text with button",
//the name of the icon on the toolbox. We will leave it empty to use the standard one
iconName: "",
//If the widgets depends on third-party library(s) then here you may check if this library(s) is loaded
widgetIsLoaded: function () {
//return typeof $ == "function" && !!$.fn.select2; //return true if jQuery and select2 widget are loaded on the page
return true; //we do not require anything so we just return true.
},
//SurveyJS library calls this function for every question to check, if it should use this widget instead of default rendering/behavior
isFit: function (question) {
//we return true if the type of question is textwithbutton
return question.getType() === "textwithbutton";
//the following code will activate the widget for a text question with inputType equals to date
//return question.getType() === 'text' && question.inputType === "date";
},
//Use this function to create a new class or add new properties or remove unneeded properties from your widget
//activatedBy tells how your widget has been activated by: property, type or customType
//property - it means that it will activated if a property of the existing question type is set to particular value, for example inputType = "date"
//type - you are changing the behaviour of entire question type. For example render radiogroup question differently, have a fancy radio buttons
//customType - you are creating a new type, like in our example "textwithbutton"
activatedByChanged: function (activatedBy) {
//we do not need to check acticatedBy parameter, since we will use our widget for customType only
//We are creating a new class and derived it from text question type. It means that text model (properties and fuctions) will be available to us
Survey.JsonObject.metaData.addClass("textwithbutton", [], null, "text");
//signaturepad is derived from "empty" class - basic question class
//Survey.JsonObject.metaData.addClass("signaturepad", [], null, "empty");
//Add new property(s)
//For more information go to https://surveyjs.io/Examples/Builder/?id=addproperties#content-docs
Survey.JsonObject.metaData.addProperties("textwithbutton", [
{ name: "buttonText", default: "Click Me" },
]);
},
//If you want to use the default question rendering then set this property to true. We do not need any default rendering, we will use our our htmlTemplate
isDefaultRender: false,
//You should use it if your set the isDefaultRender to false
htmlTemplate: "<div><input /><button></button></div>",
//The main function, rendering and two-way binding
afterRender: function (question, el) {
//el is our root element in htmlTemplate, is "div" in our case
//get the text element
var text = el.getElementsByTagName("input")[0];
//set some properties
text.inputType = question.inputType;
text.placeholder = question.placeHolder;
//get button and set some rpoeprties
var button = el.getElementsByTagName("button")[0];
button.innerText = question.buttonText;
button.onclick = function () {
question.value = "You have clicked me";
};
//set the changed value into question value
text.onchange = function () {
question.value = text.value;
};
var onValueChangedCallback = function () {
text.value = question.value ? question.value : "";
};
var onReadOnlyChangedCallback = function () {
if (question.isReadOnly) {
text.setAttribute("disabled", "disabled");
button.setAttribute("disabled", "disabled");
} else {
text.removeAttribute("disabled");
button.removeAttribute("disabled");
}
};
//if question becomes readonly/enabled add/remove disabled attribute
question.readOnlyChangedCallback = onReadOnlyChangedCallback;
//if the question value changed in the code, for example you have changed it in JavaScript
question.valueChangedCallback = onValueChangedCallback;
//set initial value
onValueChangedCallback();
//make elements disabled if needed
onReadOnlyChangedCallback();
},
//Use it to destroy the widget. It is typically needed by jQuery widgets
willUnmount: function (question, el) {
//We do not need to clear anything in our simple example
//Here is the example to destroy the image picker
//var $el = $(el).find("select");
//$el.data('picker').destroy();
},
};
//Register our widget in singleton custom widget collection
Survey.CustomWidgetCollection.Instance.addCustomWidget(widget, "customtype");
}

View File

@ -0,0 +1,19 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-block-temp',
styles: [`
:host {
text-align: center;
}
`],
template: `
<div class="block-ui-template">
<i class="feather ft-refresh-cw icon-spin font-medium-2" aria-hidden="true"></i>
<div><strong>{{message}}</strong></div>
</div>
`
})
export class BlockTemplateComponent {
message: any;
}

View File

@ -0,0 +1,20 @@
.dropdown-menu-right {
right: 0;
left: auto !important;
}
.dropdown-menu.arrow:before {
left: 70px !important;
border-bottom-color: #ffffff;
}
.dropdown-menu.arrow:after {
top: 0px;
}
@media only screen and (max-width:767px) {
._dropdown_mob {
margin-left: 150px !important;
transform: translate(40px, 40px) !important;
}
}

View File

@ -0,0 +1,27 @@
<div class="row">
<div class="content-header-left col-md-6 col-12 mb-2 breadcrumb-new" *ngIf="breadcrumb">
<h3 class="content-header-title mb-0 d-inline-block">{{breadcrumb.mainlabel}}</h3>
<div class="row breadcrumbs-top d-inline-block">
<div class="breadcrumb-wrapper col-12">
<ol class="breadcrumb">
<li class="breadcrumb-item" *ngFor="let link of breadcrumb.links">
<a *ngIf="link.isLink" routerLink="{{link.link}}">{{link.name}}</a>
<span *ngIf="!link.isLink">{{link.name}}</span>
</li>
</ol>
</div>
</div>
</div>
<div class="content-header-right col-md-6 col-12">
<div class="d-inline-block float-md-right" ngbDropdown>
<button class="btn btn-info" id="dropdownBasic1" ngbDropdownToggle>Action</button>
<div ngbDropdownMenu class="arrow _dropdown_mob dropdown-menu-right" aria-labelledby="dropdownBasic1">
<button class="dropdown-item">Calender</button>
<button class="dropdown-item">Cart</button>
<button class="dropdown-item">Support</button>
<div class="dropdown-divider"></div>
<button class="dropdown-item">Settings</button>
</div>
</div>
</div>
</div>

View File

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

View File

@ -0,0 +1,19 @@
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: 'app-breadcrumb',
templateUrl: './breadcrumb.component.html',
styleUrls: ['./breadcrumb.component.css']
})
export class BreadcrumbComponent implements OnInit {
constructor() { }
@Input() breadcrumb: object;
ngOnInit() {
this.processBreadCrumbLinks();
}
private processBreadCrumbLinks() {
}
}

View File

@ -0,0 +1,19 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CardModule } from 'src/app/content/partials/general/card/card.module';
import { RouterModule } from '@angular/router';
import { BreadcrumbComponent } from './breadcrumb.component';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
@NgModule({
imports: [
CommonModule,
CardModule,
NgbModule,
RouterModule.forChild([])
],
declarations: [BreadcrumbComponent],
exports: [BreadcrumbComponent]
})
export class BreadcrumbModule { }

View File

@ -0,0 +1,22 @@
.tabsborder{
border-bottom: none !important;
}
.h6, h6 {
font-size: 1rem;
}
:host ::ng-deep .tab-content{
padding: 1rem;
}
:host ::ng-deep .layout_space{
padding: 0%;
}
:host ::ng-deep .nav.nav-tabs.nav-underline .nav-item a.nav-link {
padding: 0.5rem 0rem;
}
:host ::ng-deep .btn-outline-info .active {
background: rgba(0, 0, 0, .05);
}

View File

@ -0,0 +1,394 @@
<div class="customizer border-left-blue-grey border-left-lighten-4 d-none d-xl-block" id="customizer">
<a class="customizer-close" (click)="toggleCustomizer($event)"><i class="feather ft-x font-medium-3"></i></a>
<a class="customizer-toggle bg-danger box-shadow-3" (click)="toggleCustomizer($event)"><i
class="feather ft-settings font-medium-3 spinner white"></i></a>
<div class="customizer-content p-2" fxFlex="auto" [perfectScrollbar]="config">
<h4 class="text-uppercase mb-0">Theme Customizer</h4>
<hr>
<p>Customize & Preview in Real Time</p>
<h5 class="mt-1 mb-1 text-bold-500">Menu Color Options</h5>
<div class="form-group">
<!-- Outline Button group -->
<div class="btn-group customizer-sidebar-options" role="group" aria-label="Basic example">
<button type="button" class="btn btn-outline-info _light" (click)="setMenuColor('menu-light',$event)"
data-sidebar="menu-light" id="light-menu">Light Menu
</button>
<button type="button" class="btn btn-outline-info _dark active" (click)="setMenuColor('menu-dark',$event)"
data-sidebar="menu-dark" id="dark-menu">Dark Menu
</button>
</div>
</div>
<hr>
<h5 class="mt-1 text-bold-500">Layout Options</h5>
<ul class="nav nav-tabs nav-underline nav-justified layout-options tabsborder">
<div class="col-lg-12 layout_space">
<div class="ngtab">
<ul ngbNav #nav="ngbNav" class="nav-pills">
<li ngbNavItem>
<a ngbNavLink>Layout</a>
<ng-template ngbNavContent>
<div role="tabpanel" class="tab-panel active px-1 pt-1" id="tabIcon21" aria-expanded="true"
aria-labelledby="baseIcon-tab21">
<div class="custom-control custom-checkbox mb-1">
<input type="checkbox" class="custom-control-input" [checked]="_themeSettingsConfig.menu === 'collapse'" (change)="toggleFixMenu($event)"
[(ngModel)]="isCollapsedMenu" name="collapsed-sidebar" id="collapsed-sidebar" >
<label class="custom-control-label" for="collapsed-sidebar">Collapsed Menu</label>
</div>
<div class="custom-control custom-checkbox mb-1">
<input type="checkbox" class="custom-control-input"
name="fixed-layout" id="fixed-layout" (ngModelChange)="toggleLayout('fixed')" [(ngModel)]="isfixChecked">
<label class="custom-control-label" for="fixed-layout">Fixed Layout</label>
</div>
<div class="custom-control custom-checkbox mb-1">
<input type="checkbox" class="custom-control-input"
name="boxed-layout" id="boxed-layout" (ngModelChange)="toggleLayout('boxed')" [(ngModel)]="isboxChecked">
<label class="custom-control-label" for="boxed-layout">Boxed Layout</label>
</div>
<div class="custom-control custom-checkbox mb-1">
<input type="checkbox" class="custom-control-input" (change)="setLayout('static',$event)"
[(ngModel)]="isStaticLayout" name="static-layout" id="static-layout">
<label class="custom-control-label" for="static-layout">Static Layout</label>
</div>
</div>
</ng-template>
</li>
<li ngbNavItem>
<a ngbNavLink>Navigation</a>
<ng-template ngbNavContent>
<div class="tab-panel px-1 pt-1" id="tabIcon22" aria-labelledby="baseIcon-tab22">
<div class="custom-control custom-checkbox mb-1">
<input type="checkbox" class="custom-control-input" name="right-side-icons"
[(ngModel)]="isRightSideIcons" (change)="setNavigation('menu-icon-right',$event)" id="right-side-icons">
<label class="custom-control-label" for="right-side-icons">Right Side Icons</label>
</div>
<div class="custom-control custom-checkbox mb-1">
<input type="checkbox" class="custom-control-input" name="bordered-navigation"
[(ngModel)]="isBorderedNavigation" (change)="setNavigation('menu-bordered',$event)" id="bordered-navigation">
<label class="custom-control-label" for="bordered-navigation">Bordered Navigation</label>
</div>
<div class="custom-control custom-checkbox mb-1">
<input type="checkbox" class="custom-control-input" name="flipped-navigation"
[(ngModel)]="isFlippedNavigation" (change)="setNavigation('menu-flipped',$event)" id="flipped-navigation">
<label class="custom-control-label" for="flipped-navigation">Flipped Navigation</label>
</div>
<div class="custom-control custom-checkbox mb-1">
<input type="checkbox" class="custom-control-input" name="collapsible-navigation"
[(ngModel)]="isCollapsibleNavigation" (change)="setNavigation('menu-collapsible',$event)" id="collapsible-navigation">
<label class="custom-control-label" for="collapsible-navigation">Collapsible Navigation</label>
</div>
<div class="custom-control custom-checkbox mb-1">
<input type="checkbox" class="custom-control-input" name="static-navigation"
[(ngModel)]="isStaticNavigation" (change)="setNavigation('menu-static',$event)" id="static-navigation">
<label class="custom-control-label" for="static-navigation">Static Navigation</label>
</div>
</div>
</ng-template>
</li>
<li ngbNavItem>
<a ngbNavLink>Navbar</a>
<ng-template ngbNavContent>
<div class="tab-panel px-1 pt-1" id="tabIcon23" aria-labelledby="baseIcon-tab23">
<div class="custom-control custom-checkbox mb-1">
<input type="checkbox" class="custom-control-input" name="navbar-static-top"
[(ngModel)]="isStaticTop" (change)="setNavbar($event)" id="navbar-static-top">
<label class="custom-control-label" for="navbar-static-top">Static Top</label>
</div>
</div>
</ng-template>
</li>
</ul>
<div [ngbNavOutlet]="nav"></div>
</div>
</div>
</ul>
<hr>
<h5 class="mt-1 text-bold-500">Navigation Color Options</h5>
<ul class="nav nav-tabs nav-underline nav-justified color-options tabsborder">
<div class="col-lg-12 layout_space">
<div [ngbNavOutlet]="nav" class="mt-2"></div>
<div class="ngtab">
<ul ngbNav #navColor="ngbNav" class="nav-pills" (navChange)="changeNavbarFontColor($event)">
<li [ngbNavItem]="1">
<a ngbNavLink id="semi-dark">Semi Dark</a>
<ng-template ngbNavContent class="px-1" >
<div class="row">
<div class="col-6">
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-sdark-clr" checked class="custom-control-input bg-default"
(click)="setColor('bg-default')" id="opt-default">
<label class="custom-control-label" (click)="setColor('bg-default')"
for="opt-default">Default</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-sdark-clr" class="custom-control-input bg-primary"
(click)="setColor('bg-primary')" id="opt-primary">
<label class="custom-control-label" (click)="setColor('bg-primary')"
for="opt-primary">Primary</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-sdark-clr" class="custom-control-input bg-danger"
(click)="setColor('bg-danger')" id="opt-danger">
<label class="custom-control-label" (click)="setColor('bg-danger')"
for="opt-danger">Danger</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-sdark-clr" class="custom-control-input bg-success"
(click)="setColor('bg-success')" id="opt-success">
<label class="custom-control-label" (click)="setColor('bg-success')"
for="opt-success">Success</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-sdark-clr" class="custom-control-input bg-blue"
(click)="setColor('bg-blue')" id="opt-blue">
<label class="custom-control-label" (click)="setColor('bg-blue')" for="opt-blue">Blue</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-sdark-clr" class="custom-control-input bg-cyan"
(click)="setColor('bg-cyan')" id="opt-cyan">
<label class="custom-control-label" (click)="setColor('bg-cyan')" for="opt-cyan">Cyan</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-sdark-clr" class="custom-control-input bg-pink"
(click)="setColor('bg-pink')" id="opt-pink">
<label class="custom-control-label" (click)="setColor('bg-pink')" for="opt-pink">Pink</label>
</div>
</div>
</div>
</ng-template>
</li>
<li [ngbNavItem] ="2" >
<a ngbNavLink id="semi-light">Semi Light</a>
<ng-template ngbNavContent>
<div class="row">
<div class="col-6">
<h6>Solid</h6>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-blue-grey"
(click)="setColor('bg-blue-grey')" id="default">
<label class="custom-control-label" (click)="setColor('bg-blue-grey')"
for="default">Default</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-primary"
(click)="setColor('bg-primary')" id="primary">
<label class="custom-control-label" (click)="setColor('bg-primary')" for="primary">Primary</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-danger"
(click)="setColor('bg-danger')" id="danger">
<label class="custom-control-label" (click)="setColor('bg-danger')" for="danger">Danger</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-success"
(click)="setColor('bg-success')" id="success">
<label class="custom-control-label" (click)="setColor('bg-success')" for="success">Success</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-blue"
(click)="setColor('bg-blue')" id="blue">
<label class="custom-control-label" (click)="setColor('bg-blue')" for="blue">Blue</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-cyan"
(click)="setColor('bg-cyan')" id="cyan">
<label class="custom-control-label" (click)="setColor('bg-cyan')" for="cyan">Cyan</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-pink"
(click)="setColor('bg-pink')" id="pink">
<label class="custom-control-label" (click)="setColor('bg-pink')" for="pink">Pink</label>
</div>
</div>
<div class="col-6">
<h6>Gradient</h6>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-blue-grey"
(click)="setColor('bg-gradient-x-grey-blue')" id="bg-gradient-x-grey-blue">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-grey-blue')"
for="bg-gradient-x-grey-blue">Default</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-primary"
(click)="setColor('bg-gradient-x-primary')" id="bg-gradient-x-primary">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-primary')"
for="bg-gradient-x-primary">Primary</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-danger"
(click)="setColor('bg-gradient-x-danger')" id="bg-gradient-x-danger">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-danger')"
for="bg-gradient-x-danger">Danger</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-success"
(click)="setColor('bg-gradient-x-success')" id="bg-gradient-x-success">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-success')"
for="bg-gradient-x-success">Success</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-blue"
(click)="setColor('bg-gradient-x-blue')" id="bg-gradient-x-blue">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-blue')"
for="bg-gradient-x-blue">Blue</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-cyan"
(click)="setColor('bg-gradient-x-cyan')" id="bg-gradient-x-cyan">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-cyan')"
for="bg-gradient-x-cyan">Cyan</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-pink"
(click)="setColor('bg-gradient-x-pink')" id="bg-gradient-x-pink">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-pink')"
for="bg-gradient-x-pink">Pink</label>
</div>
</div>
</div>
</ng-template>
</li>
<li [ngbNavItem] = "3" >
<a ngbNavLink id="dark">Dark</a>
<ng-template ngbNavContent>
<div class="row">
<div class="col-6">
<h3>Solid</h3>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-blue-grey"
(click)="setColor('bg-blue-grey')" id="default">
<label class="custom-control-label" (click)="setColor('bg-blue-grey')"
for="default">Default</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-primary"
(click)="setColor('bg-primary')" id="primary">
<label class="custom-control-label" (click)="setColor('bg-primary')" for="primary">Primary</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-danger"
(click)="setColor('bg-danger')" id="danger">
<label class="custom-control-label" (click)="setColor('bg-danger')" for="danger">Danger</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-success"
(click)="setColor('bg-success')" id="success">
<label class="custom-control-label" (click)="setColor('bg-success')" for="success">Success</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-blue"
(click)="setColor('bg-blue')" id="blue">
<label class="custom-control-label" (click)="setColor('bg-blue')" for="blue">Blue</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-cyan"
(click)="setColor('bg-cyan')" id="cyan">
<label class="custom-control-label" (click)="setColor('bg-cyan')" for="cyan">Cyan</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-pink"
(click)="setColor('bg-pink')" id="pink">
<label class="custom-control-label" (click)="setColor('bg-pink')" for="pink">Pink</label>
</div>
</div>
<div class="col-6">
<h3>Gradient</h3>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-blue-grey"
(click)="setColor('bg-gradient-x-grey-blue')" id="bg-gradient-x-grey-blue">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-grey-blue')"
for="bg-gradient-x-grey-blue">Default</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-primary"
(click)="setColor('bg-gradient-x-primary')" id="bg-gradient-x-primary">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-primary')"
for="bg-gradient-x-primary">Primary</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-danger"
(click)="setColor('bg-gradient-x-danger')" id="bg-gradient-x-danger">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-danger')"
for="bg-gradient-x-danger">Danger</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-success"
(click)="setColor('bg-gradient-x-success')" id="bg-gradient-x-success">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-success')"
for="bg-gradient-x-success">Success</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-blue"
(click)="setColor('bg-gradient-x-blue')" id="bg-gradient-x-blue">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-blue')"
for="bg-gradient-x-blue">Blue</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-cyan"
(click)="setColor('bg-gradient-x-cyan')" id="bg-gradient-x-cyan">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-cyan')"
for="bg-gradient-x-cyan">Cyan</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-pink"
id="bg-gradient-x-pink" (click)="setColor('bg-gradient-x-pink')">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-pink')"
for="bg-gradient-x-pink">Pink</label>
</div>
</div>
</div>
</ng-template>
</li>
<li [ngbNavItem] ="4">
<a ngbNavLink id="light">Light</a>
<ng-template ngbNavContent>
<div class="tab-pane" id="clrOpt4" aria-labelledby="color-opt-4">
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-light-clr" class="custom-control-input bg-blue-grey"
(click)="setColor('bg-blue-grey bg-lighten-4')" id="light-blue-grey">
<label class="custom-control-label" (click)="setColor('bg-blue-grey bg-lighten-4')"
for="light-blue-grey">Default</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-light-clr" class="custom-control-input bg-primary"
(click)="setColor('bg-primary bg-lighten-4')" id="light-primary">
<label class="custom-control-label" (click)="setColor('bg-primary bg-lighten-4')"
for="light-primary">Primary</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-light-clr" class="custom-control-input bg-danger"
(click)="setColor('bg-danger bg-lighten-4')" id="light-danger">
<label class="custom-control-label" (click)="setColor('bg-danger bg-lighten-4')"
for="light-danger">Danger</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-light-clr" class="custom-control-input bg-success"
(click)="setColor('bg-success bg-lighten-4')" id="light-success">
<label class="custom-control-label" (click)="setColor('bg-success bg-lighten-4')"
for="light-success">Success</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-light-clr" class="custom-control-input bg-blue"
(click)="setColor('bg-blue bg-lighten-4')" id="light-blue">
<label class="custom-control-label" (click)="setColor('bg-blue bg-lighten-4')"
for="light-blue">Blue</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-light-clr" class="custom-control-input bg-cyan"
(click)="setColor('bg-cyan bg-lighten-4')" id="light-cyan">
<label class="custom-control-label" (click)="setColor('bg-cyan bg-lighten-4')"
for="light-cyan">Cyan</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-light-clr" class="custom-control-input bg-pink"
(click)="setColor('bg-pink bg-lighten-4')" id="light-pink">
<label class="custom-control-label" (click)="setColor('bg-pink bg-lighten-4')"
for="light-pink">Pink</label>
</div>
</div>
</ng-template>
</li>
</ul>
<div [ngbNavOutlet]="navColor"></div>
</div>
</div>
</ul>

View File

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

View File

@ -0,0 +1,386 @@
import { Component, OnInit, Renderer2, Inject, ViewChild, HostListener } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { NavbarService } from 'src/app/_services/navbar.service';
import { ThemeSettingsService } from '../settings/theme-settings.service';
import { MenuSettingsService } from '../settings/menu-settings.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { PerfectScrollbarConfigInterface, PerfectScrollbarComponent, PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
import { NgbNavChangeEvent } from '@ng-bootstrap/ng-bootstrap';
import { AppConstants } from 'src/app/_helpers/app.constants';
declare var require: any;
const colors = require('../../../assets/data/customizer/customizerColor.json');
@Component({
selector: 'app-customizer',
templateUrl: './customizer.component.html',
styleUrls: ['./customizer.component.css']
})
export class CustomizerComponent implements OnInit {
private _unsubscribeAll: Subject<any>;
private _unsubscribeAllMenu: Subject<any>;
public _themeCustomizerConfig: any;
public _menuCustomizerConfig: any;
public _themeSettingsConfig: any;
public selectColorClass: string;
public activebutton: any;
public isCollapsedMenu = false;
public isfixChecked = false;
public isboxChecked = false;
public isStaticLayout = false;
public isRightSideIcons = false;
public isBorderedNavigation = false;
public isFlippedNavigation = false;
public isCollapsibleNavigation = false;
public isStaticNavigation = false;
public isStaticTop = false;
public config: PerfectScrollbarConfigInterface = { wheelPropagation: false };
collapsed = true;
@ViewChild(PerfectScrollbarComponent) componentRef?: PerfectScrollbarComponent;
@ViewChild(PerfectScrollbarDirective, { static: true }) directiveRef?: PerfectScrollbarDirective;
constructor(
private _renderer: Renderer2,
@Inject(DOCUMENT) private document: Document,
private navbarService: NavbarService,
private _themeSettingsService: ThemeSettingsService,
private _menuSettingsService: MenuSettingsService
) {
this._unsubscribeAll = new Subject();
this._unsubscribeAllMenu = new Subject();
}
ngOnInit() {
// Subscribe to config changes
this._themeSettingsService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((config) => {
this._themeCustomizerConfig = config;
});
this._menuSettingsService.config
.pipe(takeUntil(this._unsubscribeAllMenu))
.subscribe((config) => {
this._menuCustomizerConfig = config;
});
this._themeSettingsService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((config) => {
this._themeSettingsConfig = config;
});
}
toggleCustomizer(event) {
const element = document.getElementById('customizer');
if (element && element.classList.contains('open')) {
this._renderer.removeClass(element, 'open');
} else {
this._renderer.addClass(element, 'open');
}
}
setLayout(layout, e) {
const footer = document.getElementById('footer');
const headerNavbar = document.getElementsByClassName('header-navbar');
const mainMenu = document.getElementsByClassName('main-menu');
if (layout === 'static' && e.currentTarget.checked === true) {
this.staticLayout(e);
} else if (layout === 'static' && e.currentTarget.checked === false) {
this._themeSettingsConfig.layout.pattern = '';
this._renderer.removeClass(headerNavbar.item(0), 'navbar-static-top');
this._renderer.removeClass(footer, 'footer-static');
this._renderer.addClass(headerNavbar.item(0), 'fixed-top');
this._renderer.addClass(document.body, 'fixed-navbar');
this._renderer.addClass(mainMenu.item(0), 'menu-fixed');
this.isStaticLayout = false;
}
}
toggleFixMenu(e) {
const toggleIcon = document.getElementsByClassName('toggle-icon');
if (this.document.body.classList.contains('menu-expanded') && e.currentTarget.checked === true) {
this._themeCustomizerConfig.navbar = 'collapse';
// show the left aside menu
this.navbarService.setFixedMenu(false);
this.document.body.classList.remove('menu-expanded');
this.document.body.classList.add('menu-collapsed');
// Change switch icon
this._renderer.removeClass(toggleIcon.item(0), 'ft-toggle-right');
this._renderer.addClass(toggleIcon.item(0), 'ft-toggle-left');
this.isCollapsedMenu = true;
} else {
this._themeCustomizerConfig.navbar = 'expand';
this.navbarService.setFixedMenu(true);
this.document.body.classList.remove('menu-collapsed');
this.document.body.classList.add('menu-expanded');
// Change switch icon
this._renderer.removeClass(toggleIcon.item(0), 'ft-toggle-left');
this._renderer.addClass(toggleIcon.item(0), 'ft-toggle-right');
this.isCollapsedMenu = false;
}
setTimeout(() => { AppConstants.fireRefreshEventOnWindow(); }, 300);
this.resetOpenMenu();
}
resetOpenMenu() {
for (let i = 0; i < this._menuCustomizerConfig.vertical_menu.items.length; i++) {
const menu = this._menuCustomizerConfig.vertical_menu.items[i];
if (!menu.submenu) {
menu['isOpen'] = false;
menu['isActive'] = false;
menu['hover'] = false;
} else if (menu.submenu) {
for (let j = 0; j < menu.submenu.items.length; j++) {
menu['isOpen'] = false;
menu['isActive'] = false;
menu['hover'] = false;
menu.submenu.items[j]['isOpen'] = false;
}
}
}
}
changeNavbarFontColor($event: NgbNavChangeEvent) {
const headerElement = document.getElementsByClassName('header-navbar');
if ($event.nextId === 1) {
console.log('hgdfh');
this._renderer.removeClass(headerElement.item(0), 'navbar-dark');
this._renderer.removeClass(headerElement.item(0), 'navbar-semi-light');
this._renderer.removeClass(headerElement.item(0), 'navbar-light');
this._renderer.addClass(headerElement.item(0), 'navbar-semi-dark');
this._themeCustomizerConfig.colorTheme = 'semi-dark';
} else if ($event.nextId === 2) {
this._renderer.removeClass(headerElement.item(0), 'navbar-dark');
this._renderer.removeClass(headerElement.item(0), 'navbar-semi-dark');
this._renderer.removeClass(headerElement.item(0), 'navbar-light');
this._renderer.addClass(headerElement.item(0), 'navbar-semi-light');
this._themeCustomizerConfig.colorTheme = 'semi-light';
} else if ($event.nextId === 3) {
this._renderer.removeClass(headerElement.item(0), 'navbar-semi-light');
this._renderer.removeClass(headerElement.item(0), 'navbar-semi-dark');
this._renderer.removeClass(headerElement.item(0), 'navbar-light');
this._renderer.addClass(headerElement.item(0), 'navbar-dark');
this._themeCustomizerConfig.colorTheme = 'dark';
} else if ($event.nextId === 4) {
this._renderer.removeClass(headerElement.item(0), 'navbar-dark');
this._renderer.removeClass(headerElement.item(0), 'navbar-semi-dark');
this._renderer.removeClass(headerElement.item(0), 'navbar-semi-light');
this._renderer.addClass(headerElement.item(0), 'navbar-light');
this._themeCustomizerConfig.colorTheme = 'light';
}
this._themeSettingsService.config = {
color: ''
};
}
setMenuColor(colorClass, event) {
const darkMenuButton = document.getElementById('dark-menu');
const lightMenuButton = document.getElementById('light-menu');
if (event.currentTarget.className === 'btn btn-outline-info _dark') {
this._renderer.removeClass(lightMenuButton, 'active');
this._renderer.addClass(darkMenuButton, 'active');
} else if (event.currentTarget.className === 'btn btn-outline-info _light') {
this._renderer.removeClass(darkMenuButton, 'active');
this._renderer.addClass(lightMenuButton, 'active');
}
this._themeSettingsService.config = {
menuColor: colorClass, // light-menu, dark-menu
};
}
setNavigation(navigationClass, event) {
const navigationElement = document.getElementById('main-menu');
const element = document.getElementById('customizer');
if (event.target.checked === true && navigationClass !== 'menu-collapsible') {
this._themeSettingsService.config = {
navigation: navigationClass
};
if (navigationClass === 'menu-flipped') {
this._renderer.removeClass(element, 'open');
} else if (navigationClass === 'menu-static') {
this._renderer.removeClass(navigationElement, 'menu-fixed');
}
} else if (event.target.checked === false && navigationClass !== 'menu-collapsible') {
this._themeSettingsConfig.navigation = AppConstants.NAVIGATION_TYPE_ACCORDATION;
this._renderer.removeClass(navigationElement, navigationClass);
this._renderer.removeClass(document.body, navigationClass);
if (navigationClass === 'menu-static') {
this._renderer.addClass(navigationElement, 'menu-fixed');
}
}
if (event.target.checked === true && navigationClass === 'menu-collapsible') {
this._themeSettingsConfig.navigation = AppConstants.NAVIGATION_TYPE_ACCORDATION;
this._renderer.removeClass(navigationElement, navigationClass);
} else if (event.target.checked === false && navigationClass === 'menu-collapsible') {
this._themeSettingsService.config = {
navigation: navigationClass
};
}
if (navigationClass === 'menu-icon-right' && event.currentTarget.checked === true) {
this.isRightSideIcons = true;
} else if (navigationClass === 'menu-icon-right' && event.currentTarget.checked === false) {
this.isRightSideIcons = false;
}
if (navigationClass === 'menu-bordered' && event.currentTarget.checked === true) {
this.isBorderedNavigation = true;
} else if (navigationClass === 'menu-bordered' && event.currentTarget.checked === false) {
this.isBorderedNavigation = false;
}
if (navigationClass === 'menu-flipped' && event.currentTarget.checked === true) {
this.isFlippedNavigation = true;
} else if (navigationClass === 'menu-flipped' && event.currentTarget.checked === false) {
this.isFlippedNavigation = false;
}
if (navigationClass === 'menu-collapsible' && event.currentTarget.checked === true) {
this.isCollapsibleNavigation = true;
} else if (navigationClass === 'menu-collapsible' && event.currentTarget.checked === false) {
this.isCollapsibleNavigation = false;
}
if (navigationClass === 'menu-static' && event.currentTarget.checked === true) {
this.isStaticNavigation = true;
} else if (navigationClass === 'menu-static' && event.currentTarget.checked === false) {
this.isStaticNavigation = false;
}
}
setNavbar(event) {
const navbarElement = document.getElementsByClassName('header-navbar');
const navigationElement = document.getElementById('main-menu');
if (event.target.checked === true) {
this._renderer.removeClass(document.body, 'fixed-navbar');
this._renderer.removeClass(navbarElement.item(0), 'fixed-top');
this._renderer.removeClass(navigationElement, 'menu-fixed');
this._renderer.addClass(navbarElement.item(0), 'navbar-static-top');
this._renderer.addClass(navigationElement, 'menu-static');
this.isStaticTop = true;
} else if (event.target.checked === false) {
this._renderer.removeClass(navbarElement.item(0), 'navbar-static-top');
this._renderer.removeClass(navigationElement, 'menu-static');
this._renderer.addClass(document.body, 'fixed-navbar');
this._renderer.addClass(navbarElement.item(0), 'fixed-top');
this._renderer.addClass(navigationElement, 'menu-fixed');
this.isStaticTop = false;
}
}
setColor(colorClass) {
for (let i = 0; i <= colors.colorArray.length; i++) {
if (colorClass === colors.colorArray[i].cssClass) {
this.selectColorClass = colorClass;
break;
}
}
this._themeSettingsService.config = {
color: this.selectColorClass
};
}
toggleLayout(layout) {
const footer = document.getElementById('footer');
const headerNavbar = document.getElementsByClassName('header-navbar');
if (layout === 'boxed' && this.isboxChecked === false) {
this.boxedLayout();
setTimeout(() => { AppConstants.fireRefreshEventOnWindow(); }, 300);
} else if (layout === 'boxed' && this.isboxChecked === true) {
this._renderer.removeClass(headerNavbar.item(0), 'container');
this._renderer.removeClass(headerNavbar.item(0), 'boxed-layout');
this._renderer.removeClass(document.body, 'boxed-layout');
this._renderer.removeClass(document.body, 'container');
setTimeout(() => { AppConstants.fireRefreshEventOnWindow(); }, 300);
this._themeSettingsConfig.layout.pattern = '';
} else if (layout === 'fixed' && this.isfixChecked === false) {
this.fixedLayout();
setTimeout(() => { AppConstants.fireRefreshEventOnWindow(); }, 300);
} else if (layout === 'fixed' && this.isfixChecked === true) {
this._renderer.removeClass(footer, 'fixed-bottom');
this._themeSettingsConfig.layout.pattern = '';
setTimeout(() => { AppConstants.fireRefreshEventOnWindow(); }, 300);
}
}
fixedLayout() {
const footer = document.getElementById('footer');
const headerNavbar = document.getElementsByClassName('header-navbar');
this._renderer.removeClass(headerNavbar.item(0), 'container');
this._renderer.removeClass(headerNavbar.item(0), 'boxed-layout');
this._renderer.removeClass(document.body, 'boxed-layout');
this._renderer.removeClass(document.body, 'container');
this._renderer.addClass(footer, 'fixed-bottom');
if (this.isStaticLayout === true) {
this._renderer.addClass(headerNavbar.item(0), 'fixed-top');
this._renderer.addClass(document.body, 'fixed-navbar');
this._renderer.removeClass(footer, 'fixed-bottom');
}
this.isfixChecked = true;
this.isboxChecked = false;
this._themeSettingsConfig.layout.pattern = 'fixed';
}
boxedLayout() {
const footer = document.getElementById('footer');
const headerNavbar = document.getElementsByClassName('header-navbar');
this._renderer.removeClass(footer, 'fixed-bottom');
this._renderer.addClass(headerNavbar.item(0), 'container');
this._renderer.addClass(headerNavbar.item(0), 'boxed-layout');
this._renderer.addClass(headerNavbar.item(0), 'fixed-top');
this._renderer.addClass(document.body, 'boxed-layout');
this._renderer.addClass(document.body, 'container');
if (this.isStaticLayout === true) {
this._renderer.removeClass(headerNavbar.item(0), 'fixed-top');
this._renderer.removeClass(document.body, 'fixed-navbar');
}
this.isboxChecked = true;
this.isfixChecked = false;
this._themeSettingsConfig.layout.pattern = 'boxed';
}
staticLayout(e) {
const footer = document.getElementById('footer');
const headerNavbar = document.getElementsByClassName('header-navbar');
const mainMenu = document.getElementsByClassName('main-menu');
this._renderer.removeClass(document.body, 'fixed-navbar');
this._renderer.removeClass(headerNavbar.item(0), 'fixed-top');
this._renderer.removeClass(mainMenu.item(0), 'menu-fixed');
this._renderer.addClass(headerNavbar.item(0), 'navbar-static-top');
this._renderer.addClass(footer, 'footer-static');
this._renderer.removeClass(footer, 'fixed-bottom');
this.isStaticLayout = true;
this._themeSettingsConfig.layout.pattern = 'static';
}
@HostListener('window:resize', ['$event'])
onResize() {
if (this.document.body.classList.contains('menu-expanded')) {
this.collapsed = false;
} else {
this.collapsed = true;
}
}
}

View File

@ -0,0 +1,19 @@
.tabsborder{
border-bottom: none !important;
}
.h6, h6 {
font-size: 1rem;
}
:host ::ng-deep .tab-content{
padding: 1rem;
}
:host ::ng-deep .layout_space{
padding: 0%;
}
:host ::ng-deep .nav.nav-tabs.nav-underline .nav-item a.nav-link {
padding: 0.5rem 0rem;
}

View File

@ -0,0 +1,226 @@
<div class="customizer border-left-blue-grey border-left-lighten-4 d-none d-xl-block" id="customizer">
<a [routerLink]="" class="customizer-close" (click)="toggleCustomizer($event)"><i class="feather ft-x font-medium-3"></i></a>
<a [routerLink]="" class="customizer-toggle bg-danger box-shadow-3" (click)="toggleCustomizer($event)"><i
class="feather ft-settings font-medium-3 spinner white"></i></a>
<div class="customizer-content p-2" fxFlex="auto" [perfectScrollbar]="config">
<h4 class="text-uppercase mb-0">Theme Customizer</h4>
<hr>
<p>Customize & Preview in Real Time</p>
<h5 class="mt-1 mb-1 text-bold-500">Menu Color Options</h5>
<div class="form-group">
<!-- Outline Button group -->
<div class="btn-group customizer-sidebar-options" role="group" aria-label="Basic example">
<button type="button" class="btn btn-outline-info _light active" (click)="setMenuColor($event)"
data-sidebar="navbar-light" id="light-menu">Light Menu
</button>
<button type="button" class="btn btn-outline-info _dark" (click)="setMenuColor($event)"
data-sidebar="navbar-dark" id="dark-menu">Dark Menu
</button>
</div>
</div>
<hr>
<h5 class="mt-1 text-bold-500">Layout Options</h5>
<ul class="nav nav-tabs nav-underline nav-justified layout-options tabsborder">
<div class="col-lg-12 layout_space">
<div class="ngtab">
<ul ngbNav #nav="ngbNav" class="nav-pills">
<li ngbNavItem>
<a ngbNavLink>Layout</a>
<ng-template ngbNavContent>
<div role="tabpanel" class="tab-panel active px-1 pt-1" id="tabIcon21" aria-expanded="true"
aria-labelledby="baseIcon-tab21">
<div class="custom-control custom-checkbox mb-1">
<input type="checkbox" class="custom-control-input" (change)="toggleFixMenu($event)"
[(ngModel)]="isCollapsedMenu" name="collapsed-sidebar" id="collapsed-sidebar">
<label class="custom-control-label" for="collapsed-sidebar">Collapsed Menu</label>
</div>
<div class="custom-control custom-checkbox mb-1">
<input type="checkbox" class="custom-control-input" name="fixed-layout" id="fixed-layout"
[(ngModel)]="isfixChecked" (ngModelChange)="toggleLayout('fixed')">
<label class="custom-control-label" for="fixed-layout">Fixed Layout</label>
</div>
<div class="custom-control custom-checkbox mb-1">
<input type="checkbox" class="custom-control-input" [(ngModel)]="isboxChecked"
(ngModelChange)="toggleLayout('boxed')" name="boxed-layout" id="boxed-layout">
<label class="custom-control-label" for="boxed-layout">Boxed Layout</label>
</div>
<div class="custom-control custom-checkbox mb-1">
<input type="checkbox" class="custom-control-input" (change)="setLayout('static',$event)"
[(ngModel)]="isStaticLayout" name="static-layout" id="static-layout">
<label class="custom-control-label" for="static-layout">Static Layout</label>
</div>
</div>
</ng-template>
</li>
<li ngbNavItem>
<a ngbNavLink>Navigation</a>
<ng-template ngbNavContent>
<div class="tab-panel px-1 pt-1" id="tabIcon22" aria-labelledby="baseIcon-tab22">
<div class="custom-control custom-checkbox mb-1">
<input type="checkbox" class="custom-control-input" name="right-side-icons"
[(ngModel)]="isRightSideIcons" (click)="setNavigation('navbar-icon-right',$event)"
id="right-side-icons">
<label class="custom-control-label" for="right-side-icons">Right Side Icons</label>
</div>
</div>
</ng-template>
</li>
</ul>
<div [ngbNavOutlet]="nav"></div>
</div>
</div>
</ul>
<hr>
<h5 class="mt-1 text-bold-500">Navigation Color Options</h5>
<ul class="nav nav-tabs nav-underline nav-justified color-options tabsborder">
<div class="col-lg-12 layout_space">
<div class="ngtab">
<ul ngbNav #navColor="ngbNav" class="nav-pills" (navChange)="changeNavbarFontColor($event)">
<li [ngbNavItem]="1">
<a ngbNavLink id="dark">Dark</a>
<ng-template ngbNavContent class="px-1" >
<div class="row">
<div class="col-6">
<h3>Solid</h3>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-blue-grey"
(click)="setColor('bg-blue-grey')" id="default">
<label class="custom-control-label" (click)="setColor('bg-blue-grey')"
for="default">Default</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-primary"
(click)="setColor('bg-primary')" id="primary">
<label class="custom-control-label" (click)="setColor('bg-primary')" for="primary">Primary</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-danger"
(click)="setColor('bg-danger')" id="danger">
<label class="custom-control-label" (click)="setColor('bg-danger')" for="danger">Danger</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-success"
(click)="setColor('bg-success')" id="success">
<label class="custom-control-label" (click)="setColor('bg-success')" for="success">Success</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-blue"
(click)="setColor('bg-blue')" id="blue">
<label class="custom-control-label" (click)="setColor('bg-blue')" for="blue">Blue</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-cyan"
(click)="setColor('bg-cyan')" id="cyan">
<label class="custom-control-label" (click)="setColor('bg-cyan')" for="cyan">Cyan</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-pink"
(click)="setColor('bg-pink')" id="pink">
<label class="custom-control-label" (click)="setColor('bg-pink')" for="pink">Pink</label>
</div>
</div>
<div class="col-6">
<h3>Gradient</h3>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-blue-grey"
(click)="setColor('bg-gradient-x-grey-blue')" id="bg-gradient-x-grey-blue">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-grey-blue')"
for="bg-gradient-x-grey-blue">Default</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-primary"
(click)="setColor('bg-gradient-x-primary')" id="bg-gradient-x-primary">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-primary')"
for="bg-gradient-x-primary">Primary</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-danger"
(click)="setColor('bg-gradient-x-danger')" id="bg-gradient-x-danger">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-danger')"
for="bg-gradient-x-danger">Danger</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-success"
(click)="setColor('bg-gradient-x-success')" id="bg-gradient-x-success">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-success')"
for="bg-gradient-x-success">Success</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-blue"
(click)="setColor('bg-gradient-x-blue')" id="bg-gradient-x-blue">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-blue')"
for="bg-gradient-x-blue">Blue</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-cyan"
(click)="setColor('bg-gradient-x-cyan')" id="bg-gradient-x-cyan">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-cyan')"
for="bg-gradient-x-cyan">Cyan</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-slight-clr" class="custom-control-input bg-pink"
id="bg-gradient-x-pink" (click)="setColor('bg-gradient-x-pink')">
<label class="custom-control-label" (click)="setColor('bg-gradient-x-pink')"
for="bg-gradient-x-pink">Pink</label>
</div>
</div>
</div>
</ng-template>
</li>
<li [ngbNavItem] ="2" >
<a ngbNavLink id="light">Light</a>
<ng-template ngbNavContent>
<div class="tab-pane" id="clrOpt4" aria-labelledby="color-opt-4">
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-light-clr" class="custom-control-input bg-blue-grey"
(click)="setColor('bg-blue-grey bg-lighten-4')" id="light-blue-grey">
<label class="custom-control-label" (click)="setColor('bg-blue-grey bg-lighten-4')"
for="light-blue-grey">Default</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-light-clr" class="custom-control-input bg-primary"
(click)="setColor('bg-primary bg-lighten-4')" id="light-primary">
<label class="custom-control-label" (click)="setColor('bg-primary bg-lighten-4')"
for="light-primary">Primary</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-light-clr" class="custom-control-input bg-danger"
(click)="setColor('bg-danger bg-lighten-4')" id="light-danger">
<label class="custom-control-label" (click)="setColor('bg-danger bg-lighten-4')"
for="light-danger">Danger</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-light-clr" class="custom-control-input bg-success"
(click)="setColor('bg-success bg-lighten-4')" id="light-success">
<label class="custom-control-label" (click)="setColor('bg-success bg-lighten-4')"
for="light-success">Success</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-light-clr" class="custom-control-input bg-blue"
(click)="setColor('bg-blue bg-lighten-4')" id="light-blue">
<label class="custom-control-label" (click)="setColor('bg-blue bg-lighten-4')"
for="light-blue">Blue</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-light-clr" class="custom-control-input bg-cyan"
(click)="setColor('bg-cyan bg-lighten-4')" id="light-cyan">
<label class="custom-control-label" (click)="setColor('bg-cyan bg-lighten-4')"
for="light-cyan">Cyan</label>
</div>
<div class="custom-control custom-radio mb-1">
<input type="radio" name="nav-light-clr" class="custom-control-input bg-pink"
(click)="setColor('bg-pink bg-lighten-4')" id="light-pink">
<label class="custom-control-label" (click)="setColor('bg-pink bg-lighten-4')"
for="light-pink">Pink</label>
</div>
</div>
</ng-template>
</li>
</ul>
<div [ngbNavOutlet]="navColor"></div>
</div>
</div>
</ul>
</div>
</div>

View File

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

View File

@ -0,0 +1,273 @@
import { Component, OnInit, Renderer2, Inject, ViewChild } from '@angular/core';
import { ThemeSettingsService } from '../../settings/theme-settings.service';
import { DOCUMENT } from '@angular/common';
import { NavbarService } from 'src/app/_services/navbar.service';
import { NgbNavChangeEvent } from '@ng-bootstrap/ng-bootstrap';
import { MenuSettingsService } from '../../settings/menu-settings.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { PerfectScrollbarConfigInterface, PerfectScrollbarComponent, PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
import { AppConstants } from 'src/app/_helpers/app.constants';
declare var require: any;
const colors = require('../../../../assets/data/customizer/customizerColor.json');
@Component({
selector: 'app-horizontal-customizer',
templateUrl: './horizontal-customizer.component.html',
styleUrls: ['./horizontal-customizer.component.css']
})
export class HorizontalCustomizerComponent implements OnInit {
private _unsubscribeAll: Subject<any>;
public _themeCustomizerConfig: any;
public _menuCustomizerConfig: any;
private _themeSettingsConfig: any;
public selectColorClass: string;
public isCollapsedMenu = false;
public isfixChecked = false;
public isboxChecked = false;
public isStaticLayout = false;
public isRightSideIcons = false;
activeIdString = 'light';
public config: PerfectScrollbarConfigInterface = { wheelPropagation: false };
@ViewChild(PerfectScrollbarComponent) componentRef?: PerfectScrollbarComponent;
@ViewChild(PerfectScrollbarDirective, { static: true }) directiveRef?: PerfectScrollbarDirective;
constructor(private _renderer: Renderer2,
@Inject(DOCUMENT) private document: Document,
private navbarService: NavbarService,
private _themeSettingsService: ThemeSettingsService,
private _menuSettingsService: MenuSettingsService, ) {
this._unsubscribeAll = new Subject();
}
ngOnInit() {
this._themeSettingsService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((config) => {
this._themeCustomizerConfig = config;
});
this._themeSettingsService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((config) => {
this._themeSettingsConfig = config;
});
}
toggleCustomizer(event) {
const element = document.getElementById('customizer');
if (element && element.classList.contains('open')) {
this._renderer.removeClass(element, 'open');
} else {
this._renderer.addClass(element, 'open');
}
}
changeNavbarFontColor($event: NgbNavChangeEvent) {
const headerElement = document.getElementsByClassName('top-header');
if ($event.nextId === 1) {
this._renderer.removeClass(headerElement.item(0), 'navbar-semi-light');
this._renderer.removeClass(headerElement.item(0), 'navbar-semi-dark');
this._renderer.removeClass(headerElement.item(0), 'navbar-light');
this._renderer.removeClass(headerElement.item(0), 'navbar-shadow');
this._renderer.addClass(headerElement.item(0), 'navbar-dark');
} else if ($event.nextId === 2) {
this._renderer.removeClass(headerElement.item(0), 'navbar-semi-light');
this._renderer.removeClass(headerElement.item(0), 'navbar-semi-dark');
this._renderer.removeClass(headerElement.item(0), 'navbar-dark');
this._renderer.addClass(headerElement.item(0), 'navbar-light');
this._renderer.addClass(headerElement.item(0), 'navbar-shadow');
}
this._themeSettingsService.config = {
color: ''
};
}
setColor(colorClass) {
for (let i = 0; i <= colors.colorArray.length; i++) {
if (colorClass === colors.colorArray[i].cssClass) {
this.selectColorClass = colorClass;
break;
}
}
this._themeSettingsService.config = {
color: this.selectColorClass
};
}
setMenuColor(e) {
const darkMenuButton = document.getElementById('dark-menu');
const lightMenuButton = document.getElementById('light-menu');
const menuHeaderElement = document.getElementById('menu-header');
if (e.currentTarget.className === 'btn btn-outline-info _dark') {
this._renderer.removeClass(lightMenuButton, 'active');
this._renderer.removeClass(menuHeaderElement, 'navbar-light');
this._renderer.addClass(darkMenuButton, 'active');
this._renderer.addClass(menuHeaderElement, 'navbar-dark');
} else if (e.currentTarget.className === 'btn btn-outline-info _light') {
this._renderer.removeClass(menuHeaderElement, 'navbar-dark');
this._renderer.removeClass(darkMenuButton, 'active');
this._renderer.addClass(lightMenuButton, 'active');
this._renderer.addClass(menuHeaderElement, 'navbar-light');
}
// this._themeSettingsService.config = {
// menuColor: colorClass, // menu-dark, menu-light
// };
}
toggleFixMenu(e) {
if (this.document.body.classList.contains('menu-expanded') && e.currentTarget.checked === true) {
// show the left aside menu
this.navbarService.setFixedMenu(false);
this.document.body.classList.remove('menu-expanded');
this.document.body.classList.add('menu-collapsed');
// Change switch icon
e.srcElement.classList.remove('ft-toggle-right');
e.srcElement.classList.add('ft-toggle-left');
this.isCollapsedMenu = true;
} else {
this.navbarService.setFixedMenu(true);
this.document.body.classList.remove('menu-collapsed');
this.document.body.classList.add('menu-expanded');
// Change switch icon
e.srcElement.classList.remove('ft-toggle-left');
e.srcElement.classList.add('ft-toggle-right');
this.isCollapsedMenu = false;
}
}
setLayout(layout, e) {
const footer = document.getElementById('footer');
const headerNavbar = document.getElementsByClassName('header-navbar');
const menuHeader = document.getElementById('menu-header');
const isSticky = document.getElementsByClassName('sticky-wrapper');
const element = document.getElementById('sticky-wrapper');
if (e.currentTarget.checked === true && layout === 'static') {
// this._renderer.removeClass(headerNavbar.item(0), 'fixed-top');
this._renderer.addClass(headerNavbar.item(0), 'navbar-static-top');
this._renderer.addClass(menuHeader, 'navbar-static');
this._renderer.addClass(footer, 'footer-static');
this.isStaticLayout = true;
this._themeSettingsConfig.layout.pattern = 'static';
element.classList.add('is-static');
if (this.isboxChecked === false ) {
this._renderer.removeClass(footer, 'fixed-bottom');
}
} else {
this._themeSettingsConfig.layout.pattern = '';
this._renderer.removeClass(headerNavbar.item(0), 'navbar-static-top');
this._renderer.removeClass(footer, 'footer-static');
this._renderer.removeClass(menuHeader, 'navbar-static');
this._renderer.removeClass(isSticky.item(0), 'is-static');
this.isStaticLayout = false;
if (this.isboxChecked === true) {
this.boxedLayout();
}
if (this.isfixChecked === true) {
this.fixedLayout();
}
}
}
setNavigation(navigationClass, event) {
const navigationElement = document.getElementById('menu-header');
if (event.target.checked === true) {
this._themeSettingsService.config = {
navigation: navigationClass,
};
} else if (event.target.checked === false) {
this._renderer.removeClass(navigationElement, navigationClass);
this._renderer.removeClass(document.body, navigationClass);
}
if (navigationClass === 'menu-icon-right' && event.currentTarget.checked === true) {
this.isRightSideIcons = true;
} else if (navigationClass === 'menu-icon-right' && event.currentTarget.checked === false) {
this.isRightSideIcons = false;
}
}
toggleLayout(layout) {
const footer = document.getElementById('footer');
const headerNavbar = document.getElementsByClassName('header-navbar');
const element = document.getElementById('sticky-wrapper');
if (layout === 'boxed' && this.isboxChecked === true) {
this.boxedLayout();
setTimeout(() => { AppConstants.fireRefreshEventOnWindow(); }, 300);
} else if (layout === 'boxed' && this.isboxChecked === false) {
this._renderer.removeClass(headerNavbar.item(0), 'container');
this._renderer.removeClass(headerNavbar.item(0), 'boxed-layout');
this._renderer.removeClass(document.body, 'boxed-layout');
this._renderer.removeClass(document.body, 'container');
element.classList.remove('container');
setTimeout(() => { AppConstants.fireRefreshEventOnWindow(); }, 300);
this._themeSettingsConfig.layout.pattern = '';
} else if (layout === 'fixed' && this.isfixChecked === true) {
this.fixedLayout();
setTimeout(() => { AppConstants.fireRefreshEventOnWindow(); }, 300);
} else if (layout === 'fixed' && this.isfixChecked === false) {
this._renderer.removeClass(footer, 'fixed-bottom');
setTimeout(() => { AppConstants.fireRefreshEventOnWindow(); }, 300);
this._themeSettingsConfig.layout.pattern = '';
}
}
fixedLayout() {
const footer = document.getElementById('footer');
const headerNavbar = document.getElementsByClassName('header-navbar');
const menuHeader = document.getElementById('menu-header');
const element = document.getElementById('sticky-wrapper');
this._renderer.addClass(footer, 'fixed-bottom');
this._renderer.removeClass(document.body, 'boxed-layout');
this._renderer.removeClass(headerNavbar.item(0), 'boxed-layout');
this._renderer.removeClass(headerNavbar.item(0), 'container');
this._renderer.removeClass(document.body, 'container');
element.classList.remove('container');
if (this.isStaticLayout === true) {
this._renderer.removeClass(headerNavbar.item(0), 'fixed-top');
this._renderer.removeClass(footer, 'fixed-bottom');
this._renderer.addClass(headerNavbar.item(0), 'navbar-static-top');
this._renderer.addClass(menuHeader, 'navbar-static');
this._renderer.addClass(footer, 'footer-static');
}
this.isfixChecked = true;
this.isboxChecked = false;
this._themeSettingsConfig.layout.pattern = 'fixed';
}
boxedLayout() {
const footer = document.getElementById('footer');
const headerNavbar = document.getElementsByClassName('header-navbar');
const menuHeader = document.getElementById('menu-header');
const element = document.getElementById('sticky-wrapper');
this._renderer.removeClass(footer, 'fixed-bottom');
this._renderer.addClass(headerNavbar.item(0), 'container');
this._renderer.addClass(headerNavbar.item(0), 'boxed-layout');
this._renderer.addClass(document.body, 'boxed-layout');
this._renderer.addClass(document.body, 'container');
element.classList.add('container');
if (this.isStaticLayout === true) {
this._renderer.removeClass(headerNavbar.item(0), 'fixed-top');
this._renderer.addClass(headerNavbar.item(0), 'navbar-static-top');
this._renderer.addClass(menuHeader, 'navbar-static');
this._renderer.addClass(footer, 'footer-static');
}
this.isboxChecked = true;
this.isfixChecked = false;
this._themeSettingsConfig.layout.pattern = 'boxed';
}
}

View File

@ -0,0 +1,29 @@
<footer id="footer" class="footer footer-static footer-light navbar-border navbar-shadow" *ngIf="showFooter">
<p class="clearfix blue-grey lighten-2 text-sm-center mb-0 px-2"><span
class="float-md-left d-block d-md-inline-block">Copyright &copy; 2022 <a [routerLink]=""
class="text-bold-800 grey darken-2" href="https://themeforest.net/user/pixinvent/portfolio?ref=pixinvent"
target="_blank">PIXINVENT </a></span><span *ngIf="!hideMadeWithLove"
class="float-md-right d-block d-md-inline-block d-none d-lg-block">Hand-crafted & Made with <i
class="feather ft-heart pink"></i>
<span id="scroll-top"></span></span></p>
</footer>
<footer id="footer" class="footer fixed-bottom footer-light navbar-border navbar-shadow" *ngIf="fixedFooter">
<p class="clearfix blue-grey lighten-2 text-sm-center mb-0 px-2"><span
class="float-md-left d-block d-md-inline-block">Copyright &copy; 2022 <a [routerLink]=""
class="text-bold-800 grey darken-2" href="https://themeforest.net/user/pixinvent/portfolio?ref=pixinvent"
target="_blank">PIXINVENT </a></span><span *ngIf="!hideMadeWithLove"
class="float-md-right d-block d-md-inline-block d-none d-lg-block">Hand-crafted & Made with <i
class="feather ft-heart pink"></i>
<span id="scroll-top"></span></span></p>
</footer>
<footer id="footer" class="footer fixed-bottom footer-dark navbar-border navbar-shadow" *ngIf="darkFooter">
<p class="clearfix blue-grey lighten-2 text-sm-center mb-0 px-2"><span
class="float-md-left d-block d-md-inline-block">Copyright &copy; 2022 <a [routerLink]=""
class="text-bold-800 grey darken-2" href="https://themeforest.net/user/pixinvent/portfolio?ref=pixinvent"
target="_blank">PIXINVENT </a></span><span *ngIf="!hideMadeWithLove"
class="float-md-right d-block d-md-inline-block d-none d-lg-block">Hand-crafted & Made with <i
class="feather ft-heart pink"></i>
<span id="scroll-top"></span></span></p>
</footer>

View File

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

View File

@ -0,0 +1,77 @@
import { Component, OnInit, Renderer2 } from '@angular/core';
import { ThemeSettingsService } from '../settings/theme-settings.service';
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { Router, NavigationEnd, NavigationStart, Event } from '@angular/router';
import { FullLayoutComponent } from '../full-layout/full-layout.component';
import { AppConstants } from 'src/app/_helpers/app.constants';
@Component({
selector: 'app-footer',
templateUrl: './footer.component.html',
styleUrls: ['./footer.component.css']
})
export class FooterComponent implements OnInit {
public showFooter: boolean;
public fixedFooter: boolean;
public darkFooter: boolean;
public hideMadeWithLove: boolean;
private _unsubscribeAll: Subject<any>;
private _themeSettingsConfig: any;
constructor(private renderer: Renderer2,
private _renderer: Renderer2,
private router: Router,
private _themeSettingsService: ThemeSettingsService) {
this._unsubscribeAll = new Subject();
this.router.events.subscribe((event: Event) => {
const footerElement = document.getElementsByClassName('footer');
if (event instanceof NavigationStart) {
// Show loading indicator
}
if (event instanceof NavigationEnd) {
if (this.router.url === '/email' && footerElement.item(0)) {
this._renderer.removeClass(footerElement.item(0), 'footer-static');
this.renderer.addClass(footerElement.item(0), 'fixed-bottom');
} else if (footerElement.item(0)) {
this._renderer.removeClass(footerElement.item(0), 'fixed-bottom');
this.renderer.addClass(footerElement.item(0), 'footer-static');
}
}
});
}
ngOnInit() {
const isMobile = window.innerWidth < AppConstants.MOBILE_RESPONSIVE_WIDTH;
if ((this.router.url.indexOf('WithNavbar') >= 0) || (this.router.url.indexOf('Advanced') >= 0) ||
(this.router.url.indexOf('searchPage') >= 0)) {
this.showFooter = false;
this.darkFooter = true;
this.fixedFooter = false;
} else if (this.router.url.indexOf('email') >= 0) {
this.showFooter = false;
this.darkFooter = false;
this.fixedFooter = true;
} else if (FullLayoutComponent) {
this.showFooter = true;
this.darkFooter = false;
this.fixedFooter = false;
} else {
this.showFooter = true;
this.darkFooter = false;
this.fixedFooter = false;
}
if (isMobile) {
this.hideMadeWithLove = true;
}
// Subscribe to config changes
this._themeSettingsService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((config) => {
this._themeSettingsConfig = config;
});
}
}

View File

@ -0,0 +1,4 @@
<app-full-layout-navbar *ngIf="showNavbar"></app-full-layout-navbar>
<router-outlet></router-outlet>
<div class="sidenav-overlay d-none" id="sidenav-overlay" (click)="rightbar($event)"></div>
<app-footer *ngIf="showFooter"></app-footer>

View File

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

View File

@ -0,0 +1,124 @@
import { Component, OnInit, Renderer2, Inject } from '@angular/core';
import { Router } from '@angular/router';
import { DOCUMENT } from '@angular/common';
@Component({
selector: 'app-full-layout',
templateUrl: './full-layout.component.html',
styleUrls: ['./full-layout.component.css']
})
export class FullLayoutComponent implements OnInit {
public showFooter = true;
public showNavbar = true;
constructor(private renderer: Renderer2,
private router: Router,
@Inject(DOCUMENT) private document: Document) {
}
ngOnInit() {
this.renderer.removeClass(document.body, 'vertical-overlay-menu');
this.renderer.removeClass(document.body, 'bg-full-screen-image');
this.renderer.removeClass(document.body, 'vertical-menu-modern');
this.renderer.addClass(document.body, 'blank-page');
this.renderer.addClass(document.body, 'pace-done');
if ((this.router.url.indexOf('WithNavbar') >= 0) || (this.router.url.indexOf('Advanced') >= 0)) {
this.showFooter = true;
this.showNavbar = true;
this.renderer.addClass(document.body, 'bg-cyan');
this.renderer.addClass(document.body, 'bg-lighten-2');
this.renderer.addClass(document.body, 'fixed-navbar');
this.renderer.removeClass(document.body, 'blank-page');
} else if (this.router.url.indexOf('WithBgImage') >= 0) {
this.showFooter = false;
this.showNavbar = false;
this.renderer.addClass(document.body, 'bg-full-screen-image');
this.renderer.removeClass(document.body, 'fixed-navbar');
} else if (this.router.url.indexOf('WithBg') >= 0) {
this.showFooter = false;
this.showNavbar = false;
this.renderer.addClass(document.body, 'bg-cyan');
this.renderer.addClass(document.body, 'bg-lighten-2');
this.renderer.removeClass(document.body, 'fixed-navbar');
} else if (this.router.url.indexOf('Simple') >= 0) {
this.showFooter = false;
this.showNavbar = false;
this.renderer.removeClass(document.body, 'fixed-navbar');
} else if (this.router.url.indexOf('searchPage') >= 0) {
this.showFooter = true;
this.showNavbar = true;
this.renderer.addClass(document.body, 'fixed-navbar');
} else if (this.router.url.indexOf('flat') >= 0) {
this.showFooter = false;
this.showNavbar = false;
this.renderer.removeClass(document.body, 'fixed-navbar');
this.renderer.addClass(document.body, 'comingsoonFlat');
} else if (this.router.url === '/others/bgImage') {
this.showFooter = false;
this.showNavbar = false;
this.renderer.removeClass(document.body, 'fixed-navbar');
this.renderer.addClass(document.body, 'comingsoonOne');
} else if (this.router.url.indexOf('bgVideo') >= 0) {
this.showFooter = false;
this.showNavbar = false;
this.renderer.removeClass(document.body, 'fixed-navbar');
this.renderer.addClass(document.body, 'comingsoonVideo');
} else if (this.router.url.indexOf('flat') >= 0) {
this.showFooter = false;
this.showNavbar = false;
this.renderer.removeClass(document.body, 'fixed-navbar');
this.renderer.addClass(document.body, 'comingsoonFlat');
} else if (this.router.url.indexOf('error400') >= 0 && this.router.url.indexOf('error400Withnavbar') <= 0 ) {
this.showFooter = false;
this.showNavbar = false;
this.renderer.removeClass(document.body, 'fixed-navbar');
} else if (this.router.url.indexOf('error401') >= 0 && this.router.url.indexOf('error401Withnavbar') <= 0 ) {
this.showFooter = false;
this.showNavbar = false;
this.renderer.removeClass(document.body, 'fixed-navbar');
} else if (this.router.url.indexOf('error403') >= 0 && this.router.url.indexOf('error403Withnavbar') <= 0 ) {
this.showFooter = false;
this.showNavbar = false;
this.renderer.removeClass(document.body, 'fixed-navbar');
} else if (this.router.url.indexOf('error404') >= 0 && this.router.url.indexOf('error404Withnavbar') <= 0 ) {
this.showFooter = false;
this.showNavbar = false;
this.renderer.removeClass(document.body, 'fixed-navbar');
} else if (this.router.url.indexOf('error500') >= 0 && this.router.url.indexOf('error500Withnavbar') <= 0 ) {
this.showFooter = false;
this.showNavbar = false;
this.renderer.removeClass(document.body, 'fixed-navbar');
} else if (this.router.url.indexOf('maintenance') >= 0 || this.router.url.indexOf('recoverPassword') >= 0) {
this.showFooter = false;
this.showNavbar = false;
this.renderer.removeClass(document.body, 'fixed-navbar');
} else if (this.router.url.indexOf('unlockUser') >= 0 ) {
this.showFooter = false;
this.showNavbar = false;
this.renderer.removeClass(document.body, 'fixed-navbar');
} else {
this.showFooter = false;
this.showNavbar = false;
this.renderer.removeClass(document.body, 'bg-cyan');
this.renderer.removeClass(document.body, 'bg-lighten-2');
}
}
rightbar(event) {
const toggle = document.getElementById('sidenav-overlay');
if (event.currentTarget.className === 'sidenav-overlay d-block') {
this.renderer.removeClass(toggle, 'd-block');
this.document.body.classList.remove('menu-open');
this.document.body.classList.add('menu-close');
this.renderer.addClass(toggle, 'd-none');
} else if (event.currentTarget.className === 'sidenav-overlay d-none') {
this.renderer.removeClass(toggle, 'd-none');
this.document.body.classList.remove('menu-close');
this.document.body.classList.add('menu-open');
this.renderer.addClass(toggle, 'd-block');
}
}
}

View File

@ -0,0 +1,11 @@
@media (min-width: 767.98px) {
.collapse:not(.show) {
display: flex !important;
}
}
@media (min-width: 767.98px) {
.justify-content-end {
display: flex !important;
}
}

View File

@ -0,0 +1,28 @@
<nav
class="header-navbar navbar-expand-md navbar navbar-with-menu navbar-without-dd-arrow fixed-top navbar-dark navbar-shadow">
<div class="navbar-wrapper">
<div class="navbar-header">
<ul class="nav navbar-nav flex-row">
<li class="nav-item mobile-menu d-md-none mr-auto"><a class="nav-link nav-menu-main menu-toggle hidden-xs"
[routerLink]="">
<i class="feather ft-menu font-large-1"></i></a></li>
<li class="nav-item"><a class="navbar-brand" [routerLink]="['/dashboard/sales']"><img class="brand-logo"
alt="modern admin logo" src="../../../../assets/images/logo/logo.png">
<h3 class="brand-text">Modern </h3>
</a></li>
<li class="nav-item d-md-none"><a class="nav-link open-navbar-container" data-toggle="collapse"
data-target="#navbar-mobile" (click)="toggleNavbar($event)"><i class="la la-ellipsis-v"></i></a></li>
</ul>
</div>
<div class="navbar-container">
<div class="collapse navbar-collapse justify-content-end" id="navbar-mobile">
<ul class="nav navbar-nav">
<li class="nav-item"><a class="nav-link mr-2 nav-link-label" [routerLink]="['/dashboard/sales']"><i
class="ficon feather ft-arrow-left"></i></a></li>
<li class="dropdown nav-item"><a class="nav-link mr-2 nav-link-label" [routerLink]=""
data-toggle="dropdown"><i class="ficon feather ft-settings"></i></a></li>
</ul>
</div>
</div>
</div>
</nav>

View File

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

View File

@ -0,0 +1,23 @@
import { Component, OnInit, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';
@Component({
selector: 'app-full-layout-navbar',
templateUrl: './full-layout-navbar.component.html',
styleUrls: ['./full-layout-navbar.component.css']
})
export class FullLayoutNavbarComponent {
constructor(
@Inject(DOCUMENT) private document: Document) { }
toggleNavbar(e) {
const navbar = this.document.getElementById('navbar-mobile');
if (navbar.classList.contains('show')) {
navbar.classList.remove('show');
} else {
navbar.classList.add('show');
}
}
}

View File

@ -0,0 +1,7 @@
<ng-container *ngIf="layout === 'vertical'">
<app-header-vertical></app-header-vertical>
</ng-container>
<ng-container *ngIf="layout === 'horizontal'" (window:resize)="onResize($event)">
<app-header-horizontal></app-header-horizontal>
</ng-container>

View File

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

View File

@ -0,0 +1,125 @@
import { Component, OnInit, Renderer2, AfterViewInit, HostListener, Inject } from '@angular/core';
import { takeUntil } from 'rxjs/operators';
import { ThemeSettingsService } from '../settings/theme-settings.service';
import { Subject } from 'rxjs';
import { AppConstants } from '../../_helpers/app.constants';
import { DeviceDetectorService } from '../../_services/device-detector.service';
import { DOCUMENT } from '@angular/common';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit, AfterViewInit {
layout: string;
private _themeSettingsConfig: any;
private _unsubscribeAll: Subject<any>;
private isMobile = false;
public selectedColorClass = '';
constructor(private _renderer: Renderer2,
@Inject(DOCUMENT) private document: Document,
private _themeSettingsService: ThemeSettingsService,
private deviceService: DeviceDetectorService) {
this._unsubscribeAll = new Subject();
}
ngOnInit() {
const self = this;
// Subscribe to config changes
this._themeSettingsService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((config) => {
this._themeSettingsConfig = config;
if (config.layout && config.layout.style &&
config.layout.style === 'vertical') {
self.layout = 'vertical';
} else {
self.layout = 'horizontal';
}
this.refreshView();
});
}
refreshView() {
const self = this;
const headerElement = document.getElementsByClassName('header-navbar');
if (headerElement.item(0)) {
let currentHeaderClassList = [];
const navbar = this.document.getElementById('navbar-mobile');
// Layout
if (self._themeSettingsConfig.layout.style === 'horizontal') {
currentHeaderClassList = ['header-navbar', 'navbar-expand-md', 'navbar', 'navbar-with-menu',
'navbar-without-dd-arrow', 'navbar-static-top'];
const topHeaderElement = document.getElementById('top-header');
if (window.innerWidth < AppConstants.MOBILE_RESPONSIVE_WIDTH_HORIZONTAL) {
currentHeaderClassList.push('fixed-top');
this._renderer.removeClass(topHeaderElement, 'navbar-brand-center');
navbar.classList.remove('show');
} else {
currentHeaderClassList.push('navbar-brand-center');
this._renderer.removeClass(topHeaderElement, 'fixed-top');
navbar.classList.add('show');
}
} else {
currentHeaderClassList = ['header-navbar', 'navbar-expand-md', 'navbar', 'navbar-with-menu', 'navbar-without-dd-arrow', 'fixed-top',
'navbar-shadow'];
if (self._themeSettingsConfig.colorTheme === 'semi-light' && self._themeSettingsConfig.layout.style === 'vertical') {
if (self._themeSettingsConfig.layout.style === 'vertical') {
// currentHeaderClassList.push('bg-info');
}
self._renderer.addClass(headerElement.item(0), 'navbar-semi-light');
self._renderer.removeClass(headerElement.item(0), 'navbar-dark');
self._renderer.removeClass(headerElement.item(0), 'navbar-semi-dark');
self._renderer.removeClass(headerElement.item(0), 'navbar-light');
} else if (self._themeSettingsConfig.colorTheme === 'semi-dark' && self._themeSettingsConfig.layout.style === 'vertical') {
self._renderer.addClass(headerElement.item(0), 'navbar-semi-dark');
self._renderer.removeClass(headerElement.item(0), 'navbar-semi-light');
self._renderer.removeClass(headerElement.item(0), 'navbar-light');
self._renderer.removeClass(headerElement.item(0), 'navbar-dark');
// self._renderer.removeClass(headerElement.item(0), 'bg-info');
} else if (self._themeSettingsConfig.colorTheme === 'dark' && self._themeSettingsConfig.layout.style === 'vertical') {
self._renderer.addClass(headerElement.item(0), 'navbar-dark');
self._renderer.removeClass(headerElement.item(0), 'navbar-semi-light');
self._renderer.removeClass(headerElement.item(0), 'navbar-light');
self._renderer.removeClass(headerElement.item(0), 'navbar-semi-dark');
// self._renderer.removeClass(headerElement.item(0), 'bg-info');
} else if (self._themeSettingsConfig.colorTheme === 'light' && self._themeSettingsConfig.layout.style === 'vertical') {
self._renderer.addClass(headerElement.item(0), 'navbar-light');
self._renderer.removeClass(headerElement.item(0), 'navbar-semi-light');
self._renderer.removeClass(headerElement.item(0), 'navbar-semi-dark');
self._renderer.removeClass(headerElement.item(0), 'navbar-dark');
// self._renderer.removeClass(headerElement.item(0), 'bg-info');
}
}
currentHeaderClassList.forEach(function (c) {
self._renderer.addClass(headerElement.item(0), c);
});
}
}
ngAfterViewInit() {
this.refreshView();
}
@HostListener('window:resize', ['$event'])
onResize(event) {
if (event.target.innerWidth < AppConstants.MOBILE_RESPONSIVE_WIDTH) {
this.isMobile = true;
} else {
this.isMobile = false;
}
this.refreshView();
}
}

View File

@ -0,0 +1,12 @@
@media (max-width: 767.98px) {
.header-navbar .navbar-header {
width: 100% !important;
top: 3px;
}
}
.dropdown-menu-right {
right: 0;
left: auto !important;
top: auto !important;
}

View File

@ -0,0 +1,215 @@
<!-- fixed-top-->
<nav
class="top-header header-navbar navbar-expand-md navbar navbar-with-menu navbar-without-dd-arrow navbar-static-top navbar-light navbar-brand-center"
id="top-header" [ngClass]="selectedHeaderNavBarClass">
<div class="navbar-wrapper">
<div id="navbar-header" class="navbar-header">
<ul class="nav navbar-nav flex-row">
<li class="nav-item mobile-menu d-md-none mr-auto" ><a
class="nav-link nav-menu-main menu-toggle hidden-xs11" (click)="toggleNavigation($event)"><i
class="feather ft-menu font-large-1" ></i></a></li>
<li class="nav-item"><a [routerLink]="['/dashboard/sales']" class="navbar-brand"><img class="brand-logo" alt="modern admin logo"
src="../../../../assets/images/logo/logo.png">
<h3 class="brand-text">{{_themeSettingsConfig.brand.brand_name}}</h3>
</a></li>
<li class="nav-item d-md-none"><a class="nav-link open-navbar-container" data-toggle="collapse"
data-target="#navbar-mobile" (click)="toggleNavbar($event)"><i class="la la-ellipsis-v"></i></a></li>
</ul>
</div>
<div class="navbar-container content">
<div class="collapse navbar-collapse show" id="navbar-mobile">
<ul class="nav navbar-nav mr-auto float-left">
<li class="nav-item d-none d-md-block"><a [routerLink]="" class="nav-link nav-menu-main menu-toggle hidden-xs"
(click)="toggleFixMenu($event)" ><i class="feather ft-menu"></i></a></li>
<li class="nav-item d-none d-md-block"><a [routerLink]="" class="nav-link nav-link-expand"
(click)="toggleFullScreen()" *ngIf ="maximize === 'on'"><i class="ficon feather ft-maximize"></i></a></li>
<li class="nav-item nav-search"><a [routerLink]="" class="nav-link nav-link-search" (click)="clickSearch()" *ngIf ="search === 'on'"><i
class="ficon feather ft-search"></i></a>
<div class="search-input" [ngClass]="{'open': isHeaderSearchOpen}">
<input class="input" type="text" placeholder="Explore Modern...">
</div>
</li>
</ul>
<ul class="nav navbar-nav float-right" >
<li class="dropdown-language nav-item" ngbDropdown *ngIf ="internationalization === 'on'">
<a [routerLink]="" class="dropdown-toggle nav-link" ngbDropdownToggle id="dropdown-flag">
<i class="flag-icon flag-icon-gb"></i><span class="selected-language"></span>
</a>
<div ngbDropdownMenu class="dropdown-menu" aria-labelledby="dropdownLangMenu">
<a [routerLink]="" class="dropdown-item">
<i class="flag-icon flag-icon-gb"></i> English
</a>
<a [routerLink]="" class="dropdown-item">
<i class="flag-icon flag-icon-fr"></i> French
</a>
<a [routerLink]="" class="dropdown-item">
<i class="flag-icon flag-icon-cn"></i> Chinese
</a>
<a [routerLink]="" class="dropdown-item">
<i class="flag-icon flag-icon-de"></i> German
</a>
</div>
</li>
<li class="dropdown-notification nav-item dropdown" ngbDropdown *ngIf ="notification === 'on'">
<a class="nav-link nav-link-label" ngbDropdownToggle>
<i class="ficon feather ft-bell"></i>
<span class="badge badge-pill badge-danger badge-up badge-glow">5</span>
</a>
<ul class="dropdown-menu-media dropdown-menu-right" ngbDropdownMenu>
<li class="dropdown-menu-header">
<h6 class="dropdown-header m-0"><span class="grey darken-2">Notifications</span></h6><span
class="notification-tag badge badge-default badge-danger float-right m-0">5 New</span>
</li>
<li class="scrollable-container media-list w-100 ps-container ps-theme-dark ps-active-y" fxFlex="auto"
[perfectScrollbar]="config">
<a href="javascript:void(0)">
<div class="media">
<div class="media-left align-self-center"><i class="feather ft-plus-square icon-bg-circle bg-cyan"></i>
</div>
<div class="media-body">
<h6 class="media-heading">You have new order!</h6>
<p class="notification-text font-small-3 text-muted">Lorem ipsum dolor sit amet, consectetuer
elit.</p><small>
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">30 minutes
ago</time></small>
</div>
</div>
</a>
<a href="javascript:void(0)">
<div class="media">
<div class="media-left align-self-center"><i
class="feather ft-download-cloud icon-bg-circle bg-red bg-darken-1"></i></div>
<div class="media-body">
<h6 class="media-heading red darken-1">99% Server load</h6>
<p class="notification-text font-small-3 text-muted">Aliquam tincidunt mauris eu risus.</p><small>
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">Five hour
ago</time></small>
</div>
</div>
</a>
<a href="javascript:void(0)">
<div class="media">
<div class="media-left align-self-center"><i
class="feather ft-alert-triangle icon-bg-circle bg-yellow bg-darken-3"></i></div>
<div class="media-body">
<h6 class="media-heading yellow darken-3">Warning notifixation</h6>
<p class="notification-text font-small-3 text-muted">Vestibulum auctor dapibus neque.</p><small>
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">Today</time></small>
</div>
</div>
</a>
<a href="javascript:void(0)">
<div class="media">
<div class="media-left align-self-center"><i class="feather ft-check-circle icon-bg-circle bg-cyan"></i>
</div>
<div class="media-body">
<h6 class="media-heading">Complete the task</h6><small>
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">Last
week</time></small>
</div>
</div>
</a>
<a href="javascript:void(0)">
<div class="media">
<div class="media-left align-self-center"><i class="feather ft-file icon-bg-circle bg-teal"></i></div>
<div class="media-body">
<h6 class="media-heading">Generate monthly report</h6><small>
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">Last
month</time></small>
</div>
</div>
</a>
</li>
<li class="dropdown-menu-footer"><a class="dropdown-item text-muted text-center"
href="javascript:void(0)">Read all notifications</a></li>
</ul>
</li>
<li class="dropdown-notification nav-item" ngbDropdown *ngIf ="email === 'on'">
<a class="nav-link nav-link-label" ngbDropdownToggle><i class="ficon feather ft-mail"></i></a>
<ul class="dropdown-menu-media dropdown-menu-right" ngbDropdownMenu>
<li class="dropdown-menu-header">
<h6 class="dropdown-header m-0"><span class="grey darken-2">Messages</span></h6><span
class="notification-tag badge badge-default badge-warning float-right m-0">4 New</span>
</li>
<li class="scrollable-container media-list w-100 ps-container ps-theme-dark ps-active-y" fxFlex="auto"
[perfectScrollbar]="config">
<a href="javascript:void(0)">
<div class="media">
<div class="media-left"><span class="avatar avatar-sm avatar-online rounded-circle"><img
src="../../../../assets/images/portrait/small/avatar-s-19.png" alt="avatar"><i></i></span></div>
<div class="media-body">
<h6 class="media-heading">Margaret Govan</h6>
<p class="notification-text font-small-3 text-muted">I like your portfolio, let's start.</p>
<small>
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">Today</time></small>
</div>
</div>
</a>
<a href="javascript:void(0)">
<div class="media">
<div class="media-left"><span class="avatar avatar-sm avatar-busy rounded-circle"><img
src="../../../../assets/images/portrait/small/avatar-s-2.png" alt="avatar"><i></i></span></div>
<div class="media-body">
<h6 class="media-heading">Bret Lezama</h6>
<p class="notification-text font-small-3 text-muted">I have seen your work, there is</p><small>
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">Tuesday</time></small>
</div>
</div>
</a>
<a href="javascript:void(0)">
<div class="media">
<div class="media-left"><span class="avatar avatar-sm avatar-online rounded-circle"><img
src="../../../../assets/images/portrait/small/avatar-s-3.png" alt="avatar"><i></i></span></div>
<div class="media-body">
<h6 class="media-heading">Carie Berra</h6>
<p class="notification-text font-small-3 text-muted">Can we have call in this week ?</p><small>
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">Friday</time></small>
</div>
</div>
</a>
<a href="javascript:void(0)">
<div class="media border_bottom">
<div class="media-left"><span class="avatar avatar-sm avatar-away rounded-circle"><img
src="../../../../assets/images/portrait/small/avatar-s-6.png" alt="avatar"><i></i></span></div>
<div class="media-body">
<h6 class="media-heading">Eric Alsobrook</h6>
<p class="notification-text font-small-3 text-muted">We have project party this saturday.</p>
<small>
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">last
month</time></small>
</div>
</div>
</a>
</li>
<li class="dropdown-menu-footer"><a class="dropdown-item text-muted text-center"
href="javascript:void(0)">Read all messages</a></li>
</ul>
</li>
<li class="dropdown-user nav-item" ngbDropdown>
<a class="nav-link dropdown-user-link" ngbDropdownToggle>
<span *ngIf="currentUser.displayName"
class="mr-1 user-name text-bold-700">{{currentUser.displayName}}</span>
<span *ngIf="!currentUser.displayName" class="mr-1 user-name text-bold-700">John Doe</span>
<span class="avatar avatar-online">
<img *ngIf="currentUser.photoURL" src="{{currentUser.photoURL}}" alt="avatar">
<img *ngIf="!currentUser.photoURL" src="../../../../assets/images/portrait/small/avatar-s-19.png"
alt="avatar">
<i></i>
</span>
</a>
<div ngbDropdownMenu class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownProfileMenu">
<a class="dropdown-item" [routerLink]="['/user/user-profile']"><i class="feather ft-user"></i> Edit Profile </a>
<a class="dropdown-item" [routerLink]="['/email']"><i class="feather ft-mail"></i> My Inbox </a>
<a class="dropdown-item" [routerLink]="['/todos']"><i class="feather ft-check-square"></i> Task </a>
<a class="dropdown-item" [routerLink]="['/chats']"><i class="feather ft-message-square"></i> Chats </a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" [routerLink]="" (click)="logout()"><i class="feather ft-power"></i> Logout</a>
</div>
</li>
</ul>
</div>
</div>
</div>
</nav>

View File

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

View File

@ -0,0 +1,280 @@
import { Component, OnInit, Inject, Renderer2, HostListener, AfterViewInit, ViewChild } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { NavbarService } from '../../../_services/navbar.service';
import { ThemeSettingsService } from '../../settings/theme-settings.service';
import { MenuSettingsService } from '../../settings/menu-settings.service';
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { AppConstants } from 'src/app/_helpers/app.constants';
import { AuthService } from 'src/app/_services/auth.service';
import { Router } from '@angular/router';
import { DeviceDetectorService } from '../../../_services/device-detector.service';
import { PerfectScrollbarConfigInterface, PerfectScrollbarComponent, PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
const docElmWithBrowsersFullScreenFunctions = document.documentElement as HTMLElement & {
mozRequestFullScreen(): Promise<void>;
webkitRequestFullscreen(): Promise<void>;
msRequestFullscreen(): Promise<void>;
};
const docWithBrowsersExitFunctions = document as Document & {
mozCancelFullScreen(): Promise<void>;
webkitExitFullscreen(): Promise<void>;
msExitFullscreen(): Promise<void>;
};
@Component({
selector: 'app-header-horizontal',
templateUrl: './horizontal.component.html',
styleUrls: ['./horizontal.component.css']
})
export class HorizontalComponent implements OnInit, AfterViewInit {
insideTm: any;
outsideTm: any;
private _unsubscribeAll: Subject<any>;
brandName: string;
brandLogo: string;
public currentUser: any;
public _themeSettingsConfig: any;
private _menuSettingsConfig: any;
public displayName: boolean;
public isHeaderSearchOpen: any;
public maximize: any;
public search: any;
public internationalization: any;
public notification: any;
public email: any;
// public collapseOne = false;
// public collapseTwo = false;
// public collapseThree = false;
public selectedHeaderNavBarClass: string;
public selectedNavBarHeaderClass: string;
placement = 'bottom-right';
public config: PerfectScrollbarConfigInterface = { wheelPropagation: false };
@ViewChild(PerfectScrollbarComponent) componentRef?: PerfectScrollbarComponent;
@ViewChild(PerfectScrollbarDirective, { static: true }) directiveRef?: PerfectScrollbarDirective;
constructor(
@Inject(DOCUMENT) private document: Document,
private _renderer: Renderer2,
private renderer: Renderer2,
private navbarService: NavbarService,
public authService: AuthService,
private router: Router,
private _menuSettingsService: MenuSettingsService,
private _themeSettingsService: ThemeSettingsService,
private deviceService: DeviceDetectorService
) {
this._unsubscribeAll = new Subject();
}
ngOnInit() {
const _self = this;
if (localStorage.getItem('currentUser')) {
this.currentUser = JSON.parse(localStorage.getItem('currentUser'));
}
// Subscribe to config changes
this._themeSettingsService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((config) => {
this._themeSettingsConfig = config;
this.refreshView();
});
this._menuSettingsService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((config) => {
this._menuSettingsConfig = config;
});
const isMobile = this.deviceService.isMobile();
this.handleBody(isMobile);
this.maximize = this._themeSettingsConfig.headerIcons.maximize;
this.search = this._themeSettingsConfig.headerIcons.search;
this.internationalization = this._themeSettingsConfig.headerIcons.internationalization;
this.notification = this._themeSettingsConfig.headerIcons.notification;
this.email = this._themeSettingsConfig.headerIcons.email;
}
ngAfterViewInit(): void {
this.refreshView();
}
handleBody(isMobile: boolean) {
const _self = this;
let currentBodyClassList = [];
if (window.innerWidth < AppConstants.MOBILE_RESPONSIVE_WIDTH_HORIZONTAL && this._themeSettingsConfig.layout.style === 'horizontal') {
currentBodyClassList = ['horizontal-layout', '2-columns', 'vertical-overlay-menu', 'menu-hide'];
currentBodyClassList.push('fixed-navbar');
}
currentBodyClassList.forEach(function (c) {
_self.renderer.addClass(document.body, c);
});
}
logout() {
if (localStorage.getItem('currentUser')) {
this.authService.doLogout().then(res => {
this.router.navigate(['/login']);
}, err => {
console.log(err);
});
}
}
refreshView() {
const topHeaderElement = document.getElementsByClassName('top-header');
const menuColorElement = document.getElementsByClassName('menu-header');
const navigationElement = document.getElementsByClassName('menu-header');
if (topHeaderElement) {
if (this._themeSettingsConfig.colorTheme === 'light') {
this._renderer.removeClass(topHeaderElement.item(0), 'navbar-dark');
this._renderer.addClass(topHeaderElement.item(0), 'navbar-light');
} else if (this._themeSettingsConfig.colorTheme === 'dark') {
this._renderer.addClass(topHeaderElement.item(0), 'navbar-dark');
this._renderer.removeClass(topHeaderElement.item(0), 'navbar-light');
}
}
if (this._themeSettingsConfig.layout.style === 'horizontal') {
this.selectedHeaderNavBarClass = this._themeSettingsConfig.color;
} else if (this._themeSettingsConfig.layout.style === 'horizontal') {
this.selectedHeaderNavBarClass = this._themeSettingsConfig.color;
}
if (navigationElement) {
if (this._themeSettingsConfig.navigation === 'navbar-icon-right') {
this._renderer.addClass(navigationElement.item(0), 'navbar-icon-right');
}
}
if (menuColorElement) {
if (this._themeSettingsConfig.menuColor === 'navbar-dark') {
this._renderer.removeClass(menuColorElement.item(0), 'navbar-light');
this._renderer.addClass(menuColorElement.item(0), 'navbar-dark');
} else if (this._themeSettingsConfig.menuColor === 'navbar-light') {
this._renderer.removeClass(menuColorElement.item(0), 'navbar-dark');
this._renderer.addClass(menuColorElement.item(0), 'navbar-light');
}
}
}
toggleFixMenu(e) {
if (this.document.body.classList.contains('menu-expanded')) {
// show the left aside menu
this.document.body.classList.remove('menu-expanded');
this.document.body.classList.add('menu-collapsed');
} else {
this.document.body.classList.remove('menu-collapsed');
this.document.body.classList.add('menu-expanded');
}
}
toggleNavbar(e) {
const navbar = this.document.getElementById('navbar-mobile');
if (navbar.classList.contains('show')) {
navbar.classList.remove('show');
} else {
navbar.classList.add('show');
}
}
toggleNavigation(e) {
const sidenav = document.getElementById('sidenav-overlay');
const sidebarLeft = document.getElementById('sidebar-left') || document.getElementById('email-app-menu') ||
document.getElementById('sidebar-todo');
const contentOverlay = document.getElementById('content-overlay');
const navbar = this.document.getElementById('navbar-mobile');
if (this.document.body.classList.contains('menu-hide')) {
this.document.body.classList.remove('menu-hide');
this._renderer.removeClass(sidenav, 'd-none');
this._renderer.addClass(sidenav, 'd-block');
this.document.body.classList.remove('menu-close');
this.document.body.classList.add('menu-open');
this.document.body.classList.add('menu-expanded');
navbar.classList.remove('show');
} else if (!this.document.body.classList.contains('menu-hide') && !this.document.body.classList.contains('menu-open') ) {
this.document.body.classList.add('menu-open');
this._renderer.addClass(sidenav, 'd-block');
this._renderer.removeClass(sidenav, 'd-none');
} else {
this._renderer.removeClass(sidenav, 'd-block');
this.document.body.classList.remove('menu-open');
this.document.body.classList.add('menu-hide');
this._renderer.addClass(sidenav, 'd-none');
navbar.classList.remove('show');
}
if (sidebarLeft) {
this._renderer.removeClass(sidebarLeft, 'show');
this._renderer.removeClass(contentOverlay, 'show');
}
}
toggleFullScreen() {
const toggleIcon = document.getElementsByClassName('ficon');
if (toggleIcon.item(0).classList.contains('ft-maximize')) {
this.openfullscreen();
this._renderer.removeClass(toggleIcon.item(0), 'ft-maximize');
this._renderer.addClass(toggleIcon.item(0), 'ft-minimize');
} else if (toggleIcon.item(0).classList.contains('ft-minimize')) {
this.closefullscreen();
this._renderer.addClass(toggleIcon.item(0), 'ft-maximize');
this._renderer.removeClass(toggleIcon.item(0), 'ft-minimize');
}
}
openfullscreen() {
// Trigger fullscreen
// eslint-disable-next-line no-shadow,@typescript-eslint/no-shadow
const docElmWithBrowsersFullScreenFunctions = document.documentElement as HTMLElement & {
mozRequestFullScreen(): Promise<void>;
webkitRequestFullscreen(): Promise<void>;
msRequestFullscreen(): Promise<void>;
};
if (docElmWithBrowsersFullScreenFunctions.requestFullscreen) {
docElmWithBrowsersFullScreenFunctions.requestFullscreen();
} else if (docElmWithBrowsersFullScreenFunctions.mozRequestFullScreen) { /* Firefox */
docElmWithBrowsersFullScreenFunctions.mozRequestFullScreen();
} else if (docElmWithBrowsersFullScreenFunctions.webkitRequestFullscreen) { /* Chrome, Safari and Opera */
docElmWithBrowsersFullScreenFunctions.webkitRequestFullscreen();
} else if (docElmWithBrowsersFullScreenFunctions.msRequestFullscreen) { /* IE/Edge */
docElmWithBrowsersFullScreenFunctions.msRequestFullscreen();
}
}
closefullscreen() {
// eslint-disable-next-line no-shadow, @typescript-eslint/no-shadow
const docWithBrowsersExitFunctions = document as Document & {
mozCancelFullScreen(): Promise<void>;
webkitExitFullscreen(): Promise<void>;
msExitFullscreen(): Promise<void>;
};
if (docWithBrowsersExitFunctions.exitFullscreen) {
docWithBrowsersExitFunctions.exitFullscreen();
} else if (docWithBrowsersExitFunctions.mozCancelFullScreen) { /* Firefox */
docWithBrowsersExitFunctions.mozCancelFullScreen();
} else if (docWithBrowsersExitFunctions.webkitExitFullscreen) { /* Chrome, Safari and Opera */
docWithBrowsersExitFunctions.webkitExitFullscreen();
} else if (docWithBrowsersExitFunctions.msExitFullscreen) { /* IE/Edge */
docWithBrowsersExitFunctions.msExitFullscreen();
}
}
@HostListener('window:resize', ['$event'])
onResize(event) {
const sidenav = document.getElementById('sidenav-overlay');
if (event.target.innerWidth <= 767) {
this.document.body.classList.add('vertical-overlay-menu');
this._renderer.removeClass(sidenav, 'd-block');
this._renderer.addClass(sidenav, 'd-none');
}
}
public clickSearch() {
if (this.isHeaderSearchOpen) {
this.isHeaderSearchOpen = false;
} else {
this.isHeaderSearchOpen = true;
}
}
}

View File

@ -0,0 +1,35 @@
.dropdown-menu-right {
right: 0;
left: auto !important;
top: auto !important;
}
.header-navbar .navbar-container ul.nav li a.dropdown-user-link .user-name {
margin-left: 0rem !important;
}
.border_bottom {
border-bottom: none !important;
}
:host ::ng-deep .dropdown-item:active {
color: #fff !important;
}
@media only screen and (max-width: 991.98px) {
.ft-toggle-right {
display: none !important;
}
.ft-toggle-left {
display: none !important;
}
.collapse:not(.show) {
display: unset !important;
}
}
.header-navbar .navbar-header .navbar-brand .brand-text {
padding-left: 11px !important;
}

View File

@ -0,0 +1,226 @@
<nav class="header-navbar navbar-expand-md navbar navbar-with-menu navbar-without-dd-arrow fixed-top navbar-shadow"
[ngClass]="selectedHeaderNavBarClass">
<div class="navbar-wrapper">
<div id="navbar-header" class="navbar-header" [ngClass]="selectedNavBarHeaderClass"
(mouseenter)="mouseEnter($event)" (mouseleave)="mouseLeave($event)">
<ul class="nav navbar-nav flex-row">
<!-- Remove position relative in responsive -->
<li class="nav-item mobile-menu d-lg-none mr-auto"><a class="nav-link nav-menu-main menu-toggle hidden-xs11"
(click)="toggleNavigation($event)">
<i class="feather ft-menu font-large-1"></i></a></li>
<li class="nav-item mr-auto"><a [routerLink]="['/dashboard/sales']" class="navbar-brand"
routerLink="/dashboard/sales"><img class="brand-logo" alt="modern admin logo"
[src]="_themeSettingsConfig.brand.logo.value">
<h3 class="brand-text">{{_themeSettingsConfig.brand.brand_name}}</h3>
</a></li>
<li class="nav-item d-none d-md-block nav-toggle">
<a [routerLink]="" class="nav-link modern-nav-toggle pr-0" data-toggle="collapse"
(click)="toggleFixMenu($event)">
<i class="feather toggle-icon font-medium-3 white"
[ngClass]="{'ft-toggle-left': _themeSettingsConfig.menu === 'collapse','ft-toggle-right': _themeSettingsConfig.menu === 'expand'}"></i>
</a>
</li>
<li class="nav-item d-lg-none"><a class="nav-link open-navbar-container" data-toggle="collapse"
data-target="#navbar-mobile" (click)="toggleNavbar($event)"><i class="la la-ellipsis-v"></i></a></li>
</ul>
</div>
<!-- New-->
<div class="navbar-container content" [hidden]="isMobile && !showNavbar">
<div class="collapse navbar-collapse" id="navbar-mobile">
<ul class="nav navbar-nav mr-auto float-left">
<li class="nav-item d-none d-md-block"><a [routerLink]="" class="nav-link nav-link-expand"
(click)="toggleFullScreen()" *ngIf="maximize === 'on'"><i class="ficon feather ft-maximize"></i></a></li>
<li class="nav-item nav-search"><a [routerLink]="" class="nav-link nav-link-search" (click)="clickSearch()"
*ngIf="search === 'on'"><i class="ficon feather ft-search"></i></a>
<div class="search-input" [ngClass]="{'open': isHeaderSearchOpen}">
<input class="input" type="text" placeholder="Explore Modern...">
</div>
</li>
</ul>
<ul class="nav navbar-nav float-right">
<li class="dropdown-language nav-item" ngbDropdown *ngIf="internationalization === 'on'">
<a [routerLink]="" class="dropdown-toggle nav-link" ngbDropdownToggle id="dropdown-flag">
<i class="flag-icon flag-icon-gb"></i><span class="selected-language"></span>
</a>
<div ngbDropdownMenu class="dropdown-menu" aria-labelledby="dropdownLangMenu">
<a [routerLink]="" class="dropdown-item">
<i class="flag-icon flag-icon-gb"></i> English
</a>
<a [routerLink]="" class="dropdown-item">
<i class="flag-icon flag-icon-fr"></i> French
</a>
<a [routerLink]="" class="dropdown-item">
<i class="flag-icon flag-icon-cn"></i> Chinese
</a>
<a [routerLink]="" class="dropdown-item">
<i class="flag-icon flag-icon-de"></i> German
</a>
</div>
</li>
<li class="dropdown-notification nav-item dropdown" ngbDropdown *ngIf="notification === 'on'">
<a class="nav-link nav-link-label" ngbDropdownToggle>
<i class="ficon feather ft-bell"></i>
<span class="badge badge-pill badge-danger badge-up badge-glow">5</span>
</a>
<ul class="dropdown-menu-media dropdown-menu-right" ngbDropdownMenu>
<li class="dropdown-menu-header">
<h6 class="dropdown-header m-0"><span class="grey darken-2">Notifications</span></h6><span
class="notification-tag badge badge-default badge-danger float-right m-0">5 New</span>
</li>
<li class="scrollable-container media-list w-100 ps-container ps-theme-dark ps-active-y" fxFlex="auto" [perfectScrollbar]="config">
<a href="javascript:void(0)">
<div class="media">
<div class="media-left align-self-center"><i
class="feather ft-plus-square icon-bg-circle bg-cyan"></i>
</div>
<div class="media-body">
<h6 class="media-heading">You have new order!</h6>
<p class="notification-text font-small-3 text-muted">Lorem ipsum dolor sit amet, consectetuer
elit.</p><small>
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">30 minutes
ago</time></small>
</div>
</div>
</a>
<a href="javascript:void(0)">
<div class="media">
<div class="media-left align-self-center"><i
class="feather ft-download-cloud icon-bg-circle bg-red bg-darken-1"></i></div>
<div class="media-body">
<h6 class="media-heading red darken-1">99% Server load</h6>
<p class="notification-text font-small-3 text-muted">Aliquam tincidunt mauris eu risus.</p><small>
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">Five hour
ago</time></small>
</div>
</div>
</a>
<a href="javascript:void(0)">
<div class="media">
<div class="media-left align-self-center"><i
class="feather ft-alert-triangle icon-bg-circle bg-yellow bg-darken-3"></i></div>
<div class="media-body">
<h6 class="media-heading yellow darken-3">Warning notifixation</h6>
<p class="notification-text font-small-3 text-muted">Vestibulum auctor dapibus neque.</p><small>
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">Today</time></small>
</div>
</div>
</a>
<a href="javascript:void(0)">
<div class="media">
<div class="media-left align-self-center"><i
class="feather ft-check-circle icon-bg-circle bg-cyan"></i>
</div>
<div class="media-body">
<h6 class="media-heading">Complete the task</h6><small>
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">Last
week</time></small>
</div>
</div>
</a>
<a href="javascript:void(0)">
<div class="media">
<div class="media-left align-self-center"><i class="feather ft-file icon-bg-circle bg-teal"></i>
</div>
<div class="media-body">
<h6 class="media-heading">Generate monthly report</h6><small>
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">Last
month</time></small>
</div>
</div>
</a>
</li>
<li class="dropdown-menu-footer"><a class="dropdown-item text-muted text-center"
href="javascript:void(0)">Read all notifications</a></li>
</ul>
</li>
<li class="dropdown-notification nav-item" ngbDropdown>
<a class="nav-link nav-link-label" ngbDropdownToggle *ngIf="email === 'on'"><i
class="ficon feather ft-mail"></i></a>
<ul class="dropdown-menu-media dropdown-menu-right" ngbDropdownMenu>
<li class="dropdown-menu-header">
<h6 class="dropdown-header m-0"><span class="grey darken-2">Messages</span></h6><span
class="notification-tag badge badge-default badge-warning float-right m-0">4 New</span>
</li>
<li class="scrollable-container media-list w-100 ps-container ps-theme-dark ps-active-y" fxFlex="auto"
[perfectScrollbar]="config">
<a href="javascript:void(0)">
<div class="media">
<div class="media-left"><span class="avatar avatar-sm avatar-online rounded-circle"><img
src="../../../assets/images/portrait/small/avatar-s-19.png" alt="avatar"><i></i></span></div>
<div class="media-body">
<h6 class="media-heading">Margaret Govan</h6>
<p class="notification-text font-small-3 text-muted">I like your portfolio, let's start.</p>
<small>
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">Today</time></small>
</div>
</div>
</a>
<a href="javascript:void(0)">
<div class="media">
<div class="media-left"><span class="avatar avatar-sm avatar-busy rounded-circle"><img
src="../../../assets/images/portrait/small/avatar-s-2.png" alt="avatar"><i></i></span></div>
<div class="media-body">
<h6 class="media-heading">Bret Lezama</h6>
<p class="notification-text font-small-3 text-muted">I have seen your work, there is</p><small>
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">Tuesday</time></small>
</div>
</div>
</a>
<a href="javascript:void(0)">
<div class="media">
<div class="media-left"><span class="avatar avatar-sm avatar-online rounded-circle"><img
src="../../../assets/images/portrait/small/avatar-s-3.png" alt="avatar"><i></i></span></div>
<div class="media-body">
<h6 class="media-heading">Carie Berra</h6>
<p class="notification-text font-small-3 text-muted">Can we have call in this week ?</p><small>
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">Friday</time></small>
</div>
</div>
</a>
<a href="javascript:void(0)">
<div class="media border_bottom">
<div class="media-left"><span class="avatar avatar-sm avatar-away rounded-circle"><img
src="../../../assets/images/portrait/small/avatar-s-6.png" alt="avatar"><i></i></span></div>
<div class="media-body">
<h6 class="media-heading">Eric Alsobrook</h6>
<p class="notification-text font-small-3 text-muted">We have project party this saturday.</p>
<small>
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">last
month</time></small>
</div>
</div>
</a>
</li>
<li class="dropdown-menu-footer"><a class="dropdown-item text-muted text-center"
href="javascript:void(0)">Read all messages</a></li>
</ul>
</li>
<li class="dropdown-user nav-item" ngbDropdown>
<a class="nav-link dropdown-user-link" ngbDropdownToggle>
<span *ngIf="currentUser.displayName"
class="mr-1 user-name text-bold-700">{{currentUser.displayName}}</span>
<span *ngIf="!currentUser.displayName" class="mr-1 user-name text-bold-700">John Doe</span>
<span class="avatar avatar-online">
<img *ngIf="currentUser.photoURL" src="{{currentUser.photoURL}}" alt="avatar">
<img *ngIf="!currentUser.photoURL" src="../../../assets/images/portrait/small/avatar-s-19.png"
alt="avatar">
<i></i>
</span>
</a>
<div ngbDropdownMenu class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownProfileMenu">
<a class="dropdown-item" [routerLink]="['/user/user-profile']"><i class="feather ft-user"></i> Edit
Profile </a>
<a class="dropdown-item" [routerLink]="['/email']"><i class="feather ft-mail"></i> My Inbox </a>
<a class="dropdown-item" [routerLink]="['/todos']"><i class="feather ft-check-square"></i> Task </a>
<a class="dropdown-item" [routerLink]="['/chats']"><i class="feather ft-message-square"></i> Chats </a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" [routerLink]="" (click)="logout()"><i class="feather ft-power"></i> Logout</a>
</div>
</li>
</ul>
</div>
</div>
<!-- New-->
</div>
</nav>

View File

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

View File

@ -0,0 +1,477 @@
import { Component, OnInit, Inject, Renderer2, ElementRef, ViewChild, AfterViewInit, HostListener } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { NavbarService } from '../../../_services/navbar.service';
import { ThemeSettingsService } from '../../settings/theme-settings.service';
import { MenuSettingsService } from '../../settings/menu-settings.service';
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { AuthService } from 'src/app/_services/auth.service';
import { Router } from '@angular/router';
import { PerfectScrollbarConfigInterface, PerfectScrollbarComponent, PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
import { AppConstants } from 'src/app/_helpers/app.constants';
const docElmWithBrowsersFullScreenFunctions = document.documentElement as HTMLElement & {
mozRequestFullScreen(): Promise<void>;
webkitRequestFullscreen(): Promise<void>;
msRequestFullscreen(): Promise<void>;
};
const docWithBrowsersExitFunctions = document as Document & {
mozCancelFullScreen(): Promise<void>;
webkitExitFullscreen(): Promise<void>;
msExitFullscreen(): Promise<void>;
};
@Component({
selector: 'app-header-vertical',
templateUrl: './vertical.component.html',
styleUrls: ['./vertical.component.css']
})
export class VerticalComponent implements OnInit, AfterViewInit {
insideTm: any;
outsideTm: any;
private _unsubscribeAll: Subject<any>;
private _unsubscribeAllMenu: Subject<any>;
public _themeSettingsConfig: any;
private _menuSettingsConfig: any;
public selectedHeaderNavBarClass: string;
public selectedNavBarHeaderClass: string;
public currentUser: any;
public isHeaderSearchOpen: any;
isMobile = false;
showNavbar = false;
public maximize: any;
public search: any;
public internationalization: any;
public notification: any;
public email: any;
public config: PerfectScrollbarConfigInterface = { wheelPropagation: false };
@ViewChild(PerfectScrollbarComponent) componentRef?: PerfectScrollbarComponent;
@ViewChild(PerfectScrollbarDirective, { static: true }) directiveRef?: PerfectScrollbarDirective;
constructor(
@Inject(DOCUMENT) private document: Document,
private _renderer: Renderer2,
private navbarService: NavbarService,
private _themeSettingsService: ThemeSettingsService,
private _menuSettingsService: MenuSettingsService,
public authService: AuthService,
private router: Router,
private elementRef: ElementRef
) {
this._unsubscribeAll = new Subject();
this._unsubscribeAllMenu = new Subject();
}
logout() {
if (localStorage.getItem('currentUser')) {
this.authService.doLogout().then(res => {
window.location.href = '/login';
}, err => {
console.log(err);
});
}
}
ngOnInit() {
this.isMobile = window.innerWidth < AppConstants.MOBILE_RESPONSIVE_WIDTH;
if (!this.isMobile) {
this.showNavbar = true;
}
if (localStorage.getItem('currentUser')) {
this.currentUser = JSON.parse(localStorage.getItem('currentUser'));
}
// Subscribe to config changes
this._themeSettingsService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((config) => {
this._themeSettingsConfig = config;
this.refreshView();
});
this._menuSettingsService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((config) => {
this._menuSettingsConfig = config;
});
this.maximize = this._themeSettingsConfig.headerIcons.maximize;
this.search = this._themeSettingsConfig.headerIcons.search;
this.internationalization = this._themeSettingsConfig.headerIcons.internationalization;
this.notification = this._themeSettingsConfig.headerIcons.notification;
this.email = this._themeSettingsConfig.headerIcons.email;
}
ngAfterViewInit(): void {
this.refreshView();
}
refreshView() {
const iconElement = document.getElementsByClassName('toggle-icon');
const menuColorElement = document.getElementsByClassName('main-menu');
const navigationElement = document.getElementsByClassName('main-menu');
const navbarElement = document.getElementsByClassName('header-navbar');
const themeColorElement = document.getElementsByClassName('header-navbar');
const element = document.getElementsByClassName('navbar-header');
const boxelement = document.getElementById('customizer');
if (iconElement) {
if (this._themeSettingsConfig.colorTheme === 'semi-light' || this._themeSettingsConfig.colorTheme === 'light') {
this._renderer.removeClass(iconElement.item(0), 'white');
this._renderer.addClass(iconElement.item(0), 'blue-grey');
this._renderer.addClass(iconElement.item(0), 'darken-3');
} else if (this._themeSettingsConfig.colorTheme === 'semi-dark' || this._themeSettingsConfig.colorTheme === 'dark') {
this._renderer.addClass(iconElement.item(0), 'white');
this._renderer.removeClass(iconElement.item(0), 'blue-grey');
this._renderer.removeClass(iconElement.item(0), 'darken-3');
}
}
if (this._themeSettingsConfig.colorTheme === 'semi-light') {
this.selectedHeaderNavBarClass = this._themeSettingsConfig.color;
this.selectedNavBarHeaderClass = '';
} else if (this._themeSettingsConfig.colorTheme === 'semi-dark') {
this.selectedNavBarHeaderClass = this._themeSettingsConfig.color;
this.selectedHeaderNavBarClass = '';
} else if (this._themeSettingsConfig.colorTheme === 'dark') {
this.selectedHeaderNavBarClass = this._themeSettingsConfig.color;
this.selectedNavBarHeaderClass = '';
} else if (this._themeSettingsConfig.colorTheme === 'light') {
this.selectedHeaderNavBarClass = this._themeSettingsConfig.color;
this.selectedNavBarHeaderClass = this._themeSettingsConfig.color;
}
if (menuColorElement) {
if (this._themeSettingsConfig.menuColor === 'menu-dark') {
this._renderer.removeClass(menuColorElement.item(0), 'menu-light');
this._renderer.addClass(menuColorElement.item(0), 'menu-dark');
} else if (this._themeSettingsConfig.menuColor === 'menu-light') {
this._renderer.removeClass(menuColorElement.item(0), 'menu-dark');
this._renderer.addClass(menuColorElement.item(0), 'menu-light');
}
}
if (themeColorElement) {
if (this._themeSettingsConfig.colorTheme === 'semi-light') {
this._renderer.removeClass(themeColorElement.item(0), 'navbar-semi-dark');
this._renderer.removeClass(themeColorElement.item(0), 'navbar-dark');
this._renderer.removeClass(themeColorElement.item(0), 'navbar-light');
} else if (this._themeSettingsConfig.colorTheme === 'semi-dark') {
this._renderer.removeClass(themeColorElement.item(0), 'navbar-semi-light');
this._renderer.removeClass(themeColorElement.item(0), 'navbar-dark');
this._renderer.removeClass(themeColorElement.item(0), 'navbar-light');
} else if (this._themeSettingsConfig.colorTheme === 'dark') {
this._renderer.removeClass(themeColorElement.item(0), 'navbar-semi-dark');
this._renderer.removeClass(themeColorElement.item(0), 'navbar-semi-dark');
this._renderer.removeClass(themeColorElement.item(0), 'navbar-light');
} else if (this._themeSettingsConfig.colorTheme === 'light') {
this._renderer.removeClass(themeColorElement.item(0), 'navbar-semi-dark');
this._renderer.removeClass(themeColorElement.item(0), 'navbar-dark');
this._renderer.removeClass(themeColorElement.item(0), 'navbar-semi-light');
}
}
if (navigationElement) {
if (this._themeSettingsConfig.navigation === 'menu-native-scroll') {
this._renderer.addClass(navigationElement.item(0), 'menu-native-scroll');
} else if (this._themeSettingsConfig.navigation === 'menu-icon-right') {
this._renderer.addClass(navigationElement.item(0), 'menu-icon-right');
} else if (this._themeSettingsConfig.navigation === 'menu-bordered') {
this._renderer.addClass(navigationElement.item(0), 'menu-bordered');
} else if (this._themeSettingsConfig.navigation === 'menu-flipped') {
this._renderer.addClass(document.body, 'menu-flipped');
} else if (this._themeSettingsConfig.navigation === 'menu-collapsible') {
this._renderer.addClass(navigationElement.item(0), 'menu-collapsible');
} else if (this._themeSettingsConfig.navigation === 'menu-static') {
this._renderer.addClass(navigationElement.item(0), 'menu-static');
}
}
if (navbarElement) {
if (this._themeSettingsConfig.menu === 'navbar-static-top') {
this._renderer.addClass(navbarElement.item(0), 'navbar-static-top');
this._renderer.addClass(navigationElement.item(0), 'menu-static');
}
}
if (navbarElement) {
if (this._themeSettingsConfig.menu === 'semi-light') {
this._renderer.addClass(navbarElement.item(0), 'navbar-semi-light bg-gradient-x-grey-blue');
} else if (this._themeSettingsConfig.menu === 'semi-dark') {
this._renderer.addClass(navbarElement.item(0), 'navbar-semi-dark');
} else if (this._themeSettingsConfig.menu === 'dark') {
this._renderer.addClass(navbarElement.item(0), 'navbar-dark');
} else if (this._themeSettingsConfig.menu === 'light') {
this._renderer.addClass(navbarElement.item(0), 'navbar-light');
}
}
}
resetOpenMenu() {
for (let i = 0; i < this._menuSettingsConfig.vertical_menu.items.length; i++) {
const menu = this._menuSettingsConfig.vertical_menu.items[i];
if (!menu.submenu) {
menu['isOpen'] = false;
menu['isActive'] = false;
menu['hover'] = false;
} else if (menu.submenu) {
for (let j = 0; j < menu.submenu.items.length; j++) {
menu['isOpen'] = false;
menu['isActive'] = false;
menu['hover'] = false;
menu.submenu.items[j]['isOpen'] = false;
}
}
}
}
setOpenInNavbar(value) {
for (let i = 0; i < this._menuSettingsConfig.vertical_menu.items.length; i++) {
const menu = this._menuSettingsConfig.vertical_menu.items[i];
if (!menu.submenu &&
menu.page === this.router.url) {
menu['isOpen'] = value;
menu['isActive'] = value;
} else if (menu.submenu) {
for (let j = 0; j < menu.submenu.items.length; j++) {
if (menu.submenu.items[j].page === this.router.url) {
menu['isOpen'] = value;
menu['isActive'] = value;
menu.submenu.items[j]['isOpen'] = value;
menu.submenu.items[j]['isActive'] = value;
break;
}
}
}
}
}
/**
* Use for fixed left aside menu, to show menu on mouseenter event.
* @param e Event
*/
mouseEnter(e) {
if (this.navbarService.isFixedMenu()) {
return;
}
this.navbarService.setMouseInRegion(true);
const navBar = this.document.getElementById('navbar-header');
const mainMenu = this.document.getElementById('main-menu');
// check if the left aside menu is fixed
if (!navBar.classList.contains('expanded')) {
this._renderer.addClass(navBar, 'expanded');
this._renderer.addClass(mainMenu, 'expanded');
this.resetOpenMenu();
this.setOpenInNavbar(true);
}
}
/**
* Use for fixed left aside menu, to show menu on mouseenter event.
* @param e Event
*/
mouseLeave(event) {
if (this.navbarService.isFixedMenu()) {
return;
}
const _self = this;
const navBar = this.document.getElementById('navbar-header');
const mainMenu = this.document.getElementById('main-menu');
if (navBar && navBar.classList.contains('expanded')) {
this.insideTm = setTimeout(() => {
if (!_self.navbarService.isMouseInRegion()) {
this._renderer.removeClass(navBar, 'expanded');
this._renderer.removeClass(mainMenu, 'expanded');
this.resetOpenMenu();
this.setOpenInNavbar(false);
}
}, 100);
}
this.navbarService.setMouseInRegion(false);
}
// example to update badge value dynamically from another component
updateMenuBadgeValue() {
for (let i = 0; i < this._menuSettingsConfig.items.length; i++) {
if (this._menuSettingsConfig.items[i].badge) {
this._menuSettingsConfig.items[i].badge.value = 19;
}
}
this._menuSettingsService.config = this._menuSettingsConfig;
}
handleCollapseOfMenu(element) {
if (element.classList && element.classList.contains('has-sub') && element.classList.contains('open')) {
element.classList.remove('open');
element.classList.remove('hover');
element.classList.add('menu-collapsed-open');
}
}
handleExpandOfMenu(element) {
if (element.classList && element.classList.contains('has-sub') &&
element.classList.contains('menu-collapsed-open')) {
element.classList.remove('menu-collapsed-open');
element.classList.add('open');
element.classList.add('hover');
}
}
toggleMenu(event) {
const target = event.target || event.srcElement || event.currentTarget;
const parent = target.parentElement;
if (parent && parent.classList.contains('has-sub')) {
this.openSubMenuUsingParent(parent);
} else {
const parentOfParent = parent.parentElement;
this.openSubMenuUsingParent(parentOfParent);
}
}
openSubMenuUsingParent(parent) {
if (parent.classList && parent.classList.contains('has-sub') &&
!parent.classList.contains('open')) {
parent.classList.add('open');
} else if (parent.classList && parent.classList.contains('has-sub') &&
parent.classList.contains('open')) {
parent.classList.remove('open');
}
}
toggleFullScreen() {
const toggleIcon = document.getElementsByClassName('ficon');
if (toggleIcon.item(0).classList.contains('ft-maximize')) {
this.openfullscreen();
this._renderer.removeClass(toggleIcon.item(0), 'ft-maximize');
this._renderer.addClass(toggleIcon.item(0), 'ft-minimize');
} else if (toggleIcon.item(0).classList.contains('ft-minimize')) {
this.closefullscreen();
this._renderer.addClass(toggleIcon.item(0), 'ft-maximize');
this._renderer.removeClass(toggleIcon.item(0), 'ft-minimize');
}
}
openfullscreen() {
// Trigger fullscreen
// eslint-disable-next-line no-shadow,@typescript-eslint/no-shadow
const docElmWithBrowsersFullScreenFunctions = document.documentElement as HTMLElement & {
mozRequestFullScreen(): Promise<void>;
webkitRequestFullscreen(): Promise<void>;
msRequestFullscreen(): Promise<void>;
};
if (docElmWithBrowsersFullScreenFunctions.requestFullscreen) {
docElmWithBrowsersFullScreenFunctions.requestFullscreen();
} else if (docElmWithBrowsersFullScreenFunctions.mozRequestFullScreen) { /* Firefox */
docElmWithBrowsersFullScreenFunctions.mozRequestFullScreen();
} else if (docElmWithBrowsersFullScreenFunctions.webkitRequestFullscreen) { /* Chrome, Safari and Opera */
docElmWithBrowsersFullScreenFunctions.webkitRequestFullscreen();
} else if (docElmWithBrowsersFullScreenFunctions.msRequestFullscreen) { /* IE/Edge */
docElmWithBrowsersFullScreenFunctions.msRequestFullscreen();
}
}
closefullscreen() {
// eslint-disable-next-line no-shadow, @typescript-eslint/no-shadow
const docWithBrowsersExitFunctions = document as Document & {
mozCancelFullScreen(): Promise<void>;
webkitExitFullscreen(): Promise<void>;
msExitFullscreen(): Promise<void>;
};
if (docWithBrowsersExitFunctions.exitFullscreen) {
docWithBrowsersExitFunctions.exitFullscreen();
} else if (docWithBrowsersExitFunctions.mozCancelFullScreen) { /* Firefox */
docWithBrowsersExitFunctions.mozCancelFullScreen();
} else if (docWithBrowsersExitFunctions.webkitExitFullscreen) { /* Chrome, Safari and Opera */
docWithBrowsersExitFunctions.webkitExitFullscreen();
} else if (docWithBrowsersExitFunctions.msExitFullscreen) { /* IE/Edge */
docWithBrowsersExitFunctions.msExitFullscreen();
}
}
toggleFixMenu(e) {
if (this.document.body.classList.contains('menu-expanded')) {
// show the left aside menu
this.navbarService.setFixedMenu(false);
this.document.body.classList.remove('menu-expanded');
this.document.body.classList.add('menu-collapsed');
// Change switch icon
this._themeSettingsConfig.menu = 'collapse';
} else {
this.navbarService.setFixedMenu(true);
this.document.body.classList.remove('menu-collapsed');
this.document.body.classList.add('menu-expanded');
// Change switch icon
this._themeSettingsConfig.menu = 'expand';
}
const navBar = this.document.getElementById('navbar-header');
const mainMenu = this.document.getElementById('main-menu');
this._renderer.addClass(navBar, 'expanded');
this._renderer.addClass(mainMenu, 'expanded');
setTimeout(() => { AppConstants.fireRefreshEventOnWindow(); }, 300);
}
toggleNavigation(e) {
const sidenav = document.getElementById('sidenav-overlay');
const sidebarLeft = document.getElementById('sidebar-left') || document.getElementById('email-app-menu') ||
document.getElementById('sidebar-todo');
const contentOverlay = document.getElementById('content-overlay');
if (this.document.body.classList.contains('menu-open') && (this.router.url === '/todos' || this.router.url === '/contacts' ||
this.router.url === '/email' || this.router.url === '/chats' || this.router.url === '/chats/static-chat')) {
this.document.body.classList.remove('menu-open');
this._renderer.removeClass(sidenav, 'd-block');
this._renderer.removeClass(contentOverlay, 'show');
this.document.body.classList.add('menu-close');
this._renderer.addClass(sidenav, 'd-none');
this.showNavbar = false;
} else if (this.document.body.classList.contains('menu-open')) {
this.document.body.classList.remove('menu-open');
this._renderer.removeClass(sidenav, 'd-block');
this.document.body.classList.add('menu-close');
this._renderer.addClass(sidenav, 'd-none');
this.showNavbar = false;
} else {
this._renderer.removeClass(sidenav, 'd-none');
this.document.body.classList.remove('menu-close');
this.document.body.classList.add('menu-open');
this._renderer.addClass(sidenav, 'd-block');
this.showNavbar = false;
}
if (sidebarLeft) {
this._renderer.removeClass(sidebarLeft, 'show');
}
if(contentOverlay){
this._renderer.removeClass(contentOverlay, 'show');
}
}
toggleNavbar(e) {
if (this.showNavbar) {
this.showNavbar = false;
} else {
this.showNavbar = true;
}
}
public clickSearch() {
if (this.isHeaderSearchOpen) {
this.isHeaderSearchOpen = false;
} else {
this.isHeaderSearchOpen = true;
}
}
@HostListener('window:resize', ['$event'])
onResize(event) {
if (event.target.innerWidth < AppConstants.MOBILE_RESPONSIVE_WIDTH) {
this.isMobile = true;
this.showNavbar = false;
} else {
this.isMobile = false;
this.showNavbar = true;
}
}
}

View File

@ -0,0 +1,39 @@
.is-sticky {
width: 100%;
position: fixed;
top: 0px;
z-index: 999;
}
.container {
padding-left: 0px !important;
padding-right: 0px !important;
}
.is-static {
width: 100%;
position: sticky;
top: 0px;
z-index: 999;
}
:host ::ng-deep .navbar-dark .navbar-nav .nav-link {
color: white !important;
}
:host ::ng-deep .navbar-light .navbar-nav .nav-link {
color: #6b6f82 !important;
}
.dropdown-menu .dropdown-submenu>a:after {
top: 14px;
}
.dropdown .dropdown-menu {
min-width: 13rem !important;
}
.navbar-horizontal .dropdown-menu .dropdown-submenu>a:after,
.navbar-horizontal .dropdown-menu .dropdown-submenu>button:after {
right: 0.5rem;
}

View File

@ -0,0 +1,59 @@
<div id="sticky-wrapper" class="sticky-wrapper">
<div
class="menu-header header-navbar navbar-expand-sm navbar navbar-horizontal navbar-fixed navbar-dark navbar-without-dd-arrow navbar-shadow"
role="navigation" data-menu="menu-wrapper" (scroll)="onWindowScroll($event);" id="menu-header">
<div class="navbar-container main-menu-content" data-menu="menu-container">
<ul class="nav navbar-nav" id="main-menu-navigation" data-menu="menu-navigation">
<li *ngFor="let child of _menuSettingsConfig.horizontal_menu.items" class="nav-item" [ngClass]="{
'dropdown nav-item ':(child.title && child.submenu),
'nav-item' : true,
'open': child.isOpen,
'active': child.isSelected }" [attr.data-menu]="child.submenu? 'dropdown' : ''"
(mouseenter)="mouseEnter($event)" (mouseleave)="mouseLeave($event)">
<!-- Top Menu -->
<a class="nav-link " [ngClass]="{'dropdown-item dropdown-toggle active': child.submenu}"
[attr.data-toggle]="child.submenu? 'dropdown' : ''" (click)="toggleMenu($event, child)"
routerLink="{{child.page !== 'null'?child.page:router.url}}" *ngIf="!child.section">
<i class="la" [ngClass]="child.icon"></i><span data-i18n="nav.dash.main">{{child.title}}</span>
</a>
<ul class="dropdown-menu" *ngIf="child.submenu">
<li *ngFor="let subchild of child.submenu.items" class=""
[ngClass]="{'dropdown dropdown-submenu':(subchild.submenu), 'dropdown-divider':(subchild.title ==='horizontal-divider'), 'active': subchild.isSelected }"
(mouseenter)="mouseEnter($event)" (mouseleave)="mouseLeave($event)"
[attr.data-menu]="subchild.submenu? 'dropdown-submenu' : ''">
<a class="dropdown-item" (click)="toggleMenu($event, subchild)"
routerLink="{{subchild.page !== 'null'?subchild.page:router.url}}" data-toggle="dropdown"
*ngIf="!subchild.isExternalLink">
<i class="la" [ngClass]="subchild.icon"></i> <span data-i18n="nav.dash.main">{{subchild.title}}</span>
</a>
<a class="dropdown-item" (click)="toggleMenu($event, subchild)" [href]="subchild.page !== 'null'?subchild.page:router.url" target="_blank"
data-toggle="dropdown" *ngIf="subchild.isExternalLink">
<i class="la" [ngClass]="subchild.icon"></i> <span data-i18n="nav.dash.main">{{subchild.title}}</span>
</a>
<ul class="dropdown-menu" *ngIf="subchild.submenu">
<li *ngFor="let subchild of subchild.submenu.items"
[ngClass]="{'dropdown dropdown-submenu':(subchild.submenu), 'dropdown-divider':(subchild.title ==='horizontal-divider'), 'active': subchild.isSelected }"
(mouseenter)="mouseEnter($event)" (mouseleave)="mouseLeave($event)"
[attr.data-menu]="subchild.submenu? 'dropdown-submenu' : ''">
<a class="dropdown-item" *ngIf="!subchild.event" (click)="toggleMenu($event, subchild)"
routerLink="{{subchild.page !== 'null'?subchild.page:router.url}}" data-toggle="dropdown"><span
data-i18n="nav.dash.main">{{subchild.title}}</span></a>
<ul class="dropdown-menu" *ngIf="subchild.submenu">
<li *ngFor="let subchild of subchild.submenu.items" [ngClass]="{'active': subchild.isSelected}"
data-menu="">
<a class="dropdown-item" *ngIf="!subchild.event" (click)="toggleMenu($event, subchild)"
routerLink="{{subchild.page !== 'null'?subchild.page:router.url}}" data-toggle="dropdown"><span
data-i18n="nav.dash.main">{{subchild.title}}</span></a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>

View File

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

View File

@ -0,0 +1,259 @@
import { Component, AfterViewInit, OnInit, Renderer2, HostListener } from '@angular/core';
import { trigger, state, transition, style, animate } from '@angular/animations';
import { ThemeSettingsService } from '../../settings/theme-settings.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { MenuSettingsService } from '../../settings/menu-settings.service';
import { isArray } from 'util';
import { Router } from '@angular/router';
import { AppConstants } from 'src/app/_helpers/app.constants';
@Component({
selector: 'app-horizontalnav',
templateUrl: './horizontalnav.component.html',
styleUrls: ['./horizontalnav.component.css'],
animations: [
trigger('fade',
[
state('void', style({ opacity: 0 })),
transition(':enter', [animate(300)]),
transition(':leave', [animate(500)]),
]
)]
})
export class HorizontalnavComponent implements OnInit, AfterViewInit {
insideTm: any;
private _themeSettingsConfig: any;
private _unsubscribeAll: Subject<any>;
private _unsubscribeAllMenu: Subject<any>;
public _menuSettingsConfig: any;
loggedInUser: any;
constructor(private _themeSettingsService: ThemeSettingsService,
public _menuSettingsService: MenuSettingsService,
private _renderer: Renderer2,
private router: Router) {
this._unsubscribeAll = new Subject();
this._unsubscribeAllMenu = new Subject();
}
ngAfterViewInit(): void {
this.refreshView();
}
ngOnInit() {
// Subscribe to config changes
this._themeSettingsService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((config) => {
this._themeSettingsConfig = config;
this.refreshView();
});
this._menuSettingsService.config
.pipe(takeUntil(this._unsubscribeAllMenu))
.subscribe((config) => {
this._menuSettingsConfig = config;
});
this.setActiveRouteInNavbar();
}
setTheme(theme) {
this._themeSettingsService.config = {
colorTheme: theme, // semi-light, semi-dark
};
}
setLayout(layout) {
this._themeSettingsService.config = {
layout: {
pattern: layout
}
};
}
fixComponent(component, value) {
if (component === 'header') {
this._themeSettingsService.config = {
header: value
};
} else if (component === 'footer') {
this._themeSettingsService.config = {
footer: value
};
} else {
this._themeSettingsService.config = {
header: value,
footer: value
};
}
}
callFunction(event) {
const methodName = event.methodName;
if (this[methodName]) {
// method exists on the component
const param = event.methodParam;
if (!isArray(param)) {
this[methodName](param); // call it
} else {
this[methodName](param[0], param[1]); // call it
}
}
}
refreshView() {
const menuHeaderElement = document.getElementsByClassName('menu-header');
// Theme
if (menuHeaderElement && menuHeaderElement.length > 0) {
if (this._themeSettingsConfig.colorTheme === 'light') {
this._renderer.removeClass(menuHeaderElement.item(0), 'navbar-dark');
this._renderer.addClass(menuHeaderElement.item(0), 'navbar-light');
} else if (this._themeSettingsConfig.colorTheme === 'dark') {
this._renderer.addClass(menuHeaderElement.item(0), 'navbar-dark');
this._renderer.removeClass(menuHeaderElement.item(0), 'navbar-light');
}
if (this._themeSettingsConfig.layout.pattern === 'static') {
this._renderer.addClass(menuHeaderElement.item(0), 'menu-static');
} else if (this._themeSettingsConfig.layout.pattern === 'fixed') {
this._renderer.removeClass(menuHeaderElement.item(0), 'menu-static');
}
}
}
setActiveRouteInNavbar() {
for (let i = 0; i < this._menuSettingsConfig.horizontal_menu.items.length; i++) {
if (!this._menuSettingsConfig.horizontal_menu.items[i].submenu &&
this._menuSettingsConfig.horizontal_menu.items[i].page === this.router.url) {
this._menuSettingsConfig.horizontal_menu.items[i]['isSelected'] = true;
break;
} else if (this._menuSettingsConfig.horizontal_menu.items[i].submenu) {
// Level 1 menu
for (let j = 0; j < this._menuSettingsConfig.horizontal_menu.items[i].submenu.items.length; j++) {
if (!this._menuSettingsConfig.horizontal_menu.items[i].submenu.items[j].submenu &&
this._menuSettingsConfig.horizontal_menu.items[i].submenu.items[j].page === this.router.url) {
this._menuSettingsConfig.horizontal_menu.items[i]['isSelected'] = true;
this._menuSettingsConfig.horizontal_menu.items[i].submenu.items[j]['isSelected'] = true;
this._menuSettingsConfig.horizontal_menu.items[i].isOpen = true;
break;
} else if (this._menuSettingsConfig.horizontal_menu.items[i].submenu.items[j].submenu) {
// Level 2 menu
for (let k = 0; k < this._menuSettingsConfig.horizontal_menu.items[i].submenu.items[j].submenu.items.length; k++) {
if (this._menuSettingsConfig.horizontal_menu.items[i].submenu.items[j].submenu.items[k].page === this.router.url) {
this._menuSettingsConfig.horizontal_menu.items[i]['isSelected'] = true;
this._menuSettingsConfig.horizontal_menu.items[i].submenu.items[j]['isSelected'] = true;
this._menuSettingsConfig.horizontal_menu.items[i].isOpen = true;
this._menuSettingsConfig.horizontal_menu.items[i].submenu.items[j]['isSelected'] = true;
this._menuSettingsConfig.horizontal_menu.items[i].submenu.items[j].submenu.items[k]['isSelected'] = true;
this._menuSettingsConfig.horizontal_menu.items[i].submenu.items[j].isOpen = true;
}
}
}
}
}
}
}
toggleMenu(event, child, isSubmenuOfSubmenu) {
const toggle = document.getElementById('sidenav-overlay');
this.resetOtherActiveMenu(child, isSubmenuOfSubmenu);
this.loggedInUser = JSON.parse(localStorage.getItem('currentUser'));
child['isSelected'] = true;
if (this.router.url !== '') {
this._renderer.addClass(toggle, 'd-none');
this._renderer.removeClass(toggle, 'd-block');
}
if ( child.page === '/chats' && this.loggedInUser.email === 'john@pixinvent.com') {
this.router.navigate(['/chats/static-chat']);
} else if ( child.page === '/chats' && this.loggedInUser.email !== 'john@pixinvent.com') {
this.router.navigate(['/chats']);
}
}
resetOtherActiveMenu(selectedChild, isSubmenuOfSubmenu) {
for (let i = 0; i < this._menuSettingsConfig.horizontal_menu.items.length; i++) {
if (selectedChild.page !== 'null') {
this._menuSettingsConfig.horizontal_menu.items[i]['isSelected'] = false;
}
this.handleSubmenuItems(this._menuSettingsConfig.horizontal_menu.items[i], selectedChild, isSubmenuOfSubmenu);
}
}
handleSubmenuItems(parentItem, selectedChild, isSubmenuOfSubmenu) {
let isSelectedChildExist = false;
if (selectedChild['title'] === 'Horizontal') {
localStorage.setItem('currentLayoutStyle', AppConstants.LAYOUT_STYLE_HORIZONTAL);
window.location.reload();
} else if (selectedChild['title'] === 'Vertical') {
localStorage.setItem('currentLayoutStyle', AppConstants.LAYOUT_STYLE_VERTICAL);
window.location.reload();
} else if (parentItem['submenu'] &&
parentItem['submenu']['items'] &&
parentItem['submenu']['items'].length > 0) {
for (let j = 0; j < parentItem['submenu']['items'].length; j++) {
if (selectedChild.title === parentItem['submenu']['items'][j].title) {
isSelectedChildExist = true;
}
this.handleSubmenuItems(parentItem['submenu']['items'][j], selectedChild, isSubmenuOfSubmenu);
if (parentItem['submenu']['items'][j]['isSelected'] === true) {
isSelectedChildExist = true;
}
}
if (!isSelectedChildExist) {
parentItem['isSelected'] = false;
} else {
parentItem['isSelected'] = true;
}
} else if (parentItem.title !== selectedChild.title && !isSubmenuOfSubmenu) {
parentItem['isSelected'] = false;
}
}
@HostListener('window:scroll', ['$event'])
onWindowScroll(e) {
const element = document.getElementById('sticky-wrapper');
if (this._themeSettingsConfig.layout.style === 'horizontal') {
if (this._themeSettingsConfig.layout.pattern === 'fixed' ||
this._themeSettingsConfig.layout.pattern === '') {
if (window.pageYOffset > 70) { // 70 is the height of the horizontal header
element.classList.add('is-sticky');
element.classList.remove('container');
} else {
element.classList.remove('is-sticky');
}
} else if (this._themeSettingsConfig.layout.pattern === 'boxed') {
if (window.pageYOffset > 70) { // 70 is the height of the horizontal header
element.classList.add('is-sticky');
element.classList.add('container');
} else {
element.classList.remove('is-sticky');
element.classList.remove('container');
}
} else if (this._themeSettingsConfig.layout.pattern === 'static') {
element.classList.remove('is-sticky');
element.classList.remove('container');
element.classList.add('is-static');
}
}
}
mouseEnter(e) {
const _event = e;
_event.srcElement.classList.add('show');
}
/**
* Use for fixed left aside menu, to show menu on mouseenter event.
* @param e Event
*/
mouseLeave(event) {
const _event = event;
_event.srcElement.classList.remove('show');
}
}

View File

@ -0,0 +1,10 @@
<div (window:resize)="onResize($event)">
<app-header></app-header>
<ng-container *ngIf="layout === 'vertical' || isMobile === true">
<app-verticalnav></app-verticalnav>
</ng-container>
<ng-container *ngIf="layout === 'horizontal' && isMobile === false">
<app-horizontalnav></app-horizontalnav>
</ng-container>
</div>

View File

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

View File

@ -0,0 +1,47 @@
import { Component, OnInit, HostListener } from '@angular/core';
import { takeUntil } from 'rxjs/operators';
import { ThemeSettingsService } from '../settings/theme-settings.service';
import { Subject } from 'rxjs';
import { AppConstants } from 'src/app/_helpers/app.constants';
@Component({
selector: 'app-navigation',
templateUrl: './navigation.component.html',
styleUrls: ['./navigation.component.css']
})
export class NavigationComponent implements OnInit {
layout: string;
private _themeSettingsConfig: any;
private _unsubscribeAll: Subject<any>;
isMobile = false;
constructor(private _themeSettingsService: ThemeSettingsService) {
this._unsubscribeAll = new Subject();
}
ngOnInit() {
const self = this;
this.isMobile = window.innerWidth < AppConstants.MOBILE_RESPONSIVE_WIDTH_HORIZONTAL;
// Subscribe to config changes
this._themeSettingsService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((config) => {
this._themeSettingsConfig = config;
if (config.layout && config.layout.style &&
config.layout.style === 'vertical') {
self.layout = 'vertical';
} else {
self.layout = 'horizontal';
}
});
}
@HostListener('window:resize', ['$event'])
onResize(event) {
if (event.target.innerWidth < AppConstants.MOBILE_RESPONSIVE_WIDTH_HORIZONTAL) {
this.isMobile = true;
} else {
this.isMobile = false;
}
}
}

View File

@ -0,0 +1,57 @@
// Default theme settings configurations
export class NavigationConfig {
public config: any = {};
constructor() {
this.config = {
items: [
{
title: 'Dashboard',
root: true,
icon: 'la-home',
page: '/home',
badge: {type: 'badge-info', value: '2'}
},
{
title: 'Changelog',
root: true,
icon: 'la-file',
page: 'null',
submenu: {
items : [
{
}
]
}
},
{
title: 'Changelog',
root: true,
icon: 'la-file',
page: 'null',
badge: {type: 'badge-danger', value: '1.0'}
},
{
title: 'Support',
root: true,
icon: 'la-ellipsis-h feather ft-minus',
page: 'null'
},
{
title: 'Raise Support',
root: true,
icon: 'la-support',
page: 'null'
},
{
title: 'Documentation',
root: true,
icon: 'la-folder',
page: 'null'
}
]
};
}
}

View File

@ -0,0 +1,83 @@
<div (mouseenter)="mouseEnter($event)" (mouseleave)="mouseLeave($event)" id="main-menu"
class="main-menu menu-fixed menu-dark menu-accordion menu-shadow" data-scroll-to-active="true">
<div id="main-menu-content" class="main-menu-content ps-container ps-theme-light" fxFlex="auto"
[perfectScrollbar]="config">
<ul class="navigation navigation-main" id="main-menu-navigation" data-menu="menu-navigation">
<!-- Menu -->
{{child?child.title:''}}
<li *ngFor="let child of _menuSettingsConfig.vertical_menu.items" class="" [ngClass]="{
'has-sub': child.submenu,
'open': child.isOpen && child.submenu,
'nav-item': child.title,
'navigation-header':child.section,
'active': child.isSelected && !child.submenu,
'menu-collapsed-open': child.isSelected && child.submenu,
'hover': child.hover
}">
<!-- Section -->
<span class="menu-title" *ngIf="child.section">{{child.section}}</span>
<i class="la" *ngIf="child.section" [ngClass]="child.icon" data-toggle="tooltip" data-placement="right"
data-original-title="Support"></i>
<!-- Root Menu -->
<a *ngIf="child.title && !child.submenu && !child.excludeInVertical && !child.isExternalLink && !child.issupportExternalLink && !child.isStarterkitExternalLink"
routerLink="{{child.page !== 'null'?child.page:router.url}}" (click)="toggleMenu($event, child)">
<i class="la" [ngClass]="child.icon"></i>
<span class="menu-title" data-i18n="">{{child.title}}</span>
<span *ngIf="child.badge" class="badge badge-pill float-right"
[ngClass]="{'badge-info mr-2': child.badge.type==='badge-info' , 'badge-danger':child.badge.type==='badge-danger'}">
{{child.badge.value}}
</span>
</a>
<a *ngIf="child.title && !child.submenu && !child.excludeInVertical && child.isExternalLink"
[href]="child.page" target="_blank" (click)="toggleMenu($event, child)">
<i class="la" [ngClass]="child.icon"></i>
<span class="menu-title" data-i18n="">{{child.title}}</span>
<span *ngIf="child.badge" class="badge badge-pill float-right"
[ngClass]="{'badge-info mr-2': child.badge.type==='badge-info' , 'badge-danger':child.badge.type==='badge-danger'}">
{{child.badge.value}}
</span>
</a>
<a *ngIf="child.title && !child.submenu && !child.excludeInVertical && child.isStarterkitExternalLink"
[href]="child.page" target="_blank" (click)="toggleMenu($event, child)">
<i class="la" [ngClass]="child.icon"></i>
<span class="menu-title" data-i18n="">{{child.title}}</span>
<span *ngIf="child.badge" class="badge badge-pill float-right"
[ngClass]="{'badge-info mr-2': child.badge.type==='badge-info' , 'badge-danger':child.badge.type==='badge-danger'}">
{{child.badge.value}}
</span>
</a>
<!-- Submenu -->
<a *ngIf="child.title && child.submenu && !child.excludeInVertical"
routerLink="{{child.page !== 'null'?child.page:router.url}}" (click)="toggleMenu($event, child)">
<i class="la" [ngClass]="child.icon"></i>
<span class="menu-title" data-i18n="">{{child.title}}</span>
<span *ngIf="child.badge" class="badge badge-pill float-right"
[ngClass]="{'badge-info mr-2': child.badge.type==='badge-info' , 'badge-danger':child.badge.type==='badge-danger'}">
{{child.badge.value}}
</span>
</a>
<ul *ngIf="child.submenu" class="menu-content" [@popOverState]="child.isOpen">
<!-- Submenu of Submenu -->
<li *ngFor="let subchild of child.submenu.items" class="isShown"
[ngClass]="{'has-sub':(subchild.submenu),'active': subchild.isSelected && !subchild.submenu, 'open': subchild.isOpen && subchild.submenu}">
<a class="menu-item" *ngIf="!subchild.submenu && !subchild.excludeInVertical" (click)="toggleMenu($event, subchild, true)"
routerLink="{{subchild.page !== 'null'?subchild.page:router.url}}">{{subchild.title}}</a>
<a class="menu-item" *ngIf="subchild.submenu && !subchild.excludeInVertical" (click)="toggleMenu($event, subchild, true)"
routerLink="{{subchild.page !== 'null'?subchild.page:router.url}}">{{subchild.title}}</a>
<ul *ngIf="subchild.submenu && !subchild.excludeInVertical" class="menu-content">
<li *ngFor="let subchild of subchild.submenu.items" [ngClass]="{'active': subchild.isSelected && !subchild.submenu}">
<a class="menu-item" *ngIf="!subchild.event"
routerLink="{{subchild.page}}" (click)="toggleMenu($event, subchild, true)">{{subchild.title}}</a>
<a class="menu-item" *ngIf="subchild.event"
(click)="callFunction(subchild.event, subchild)">{{subchild.title}}</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>

View File

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

View File

@ -0,0 +1,389 @@
import { Component, Inject, OnInit, Renderer2, NgZone, ViewChild } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { NavbarService } from '../../../_services/navbar.service';
import { ThemeSettingsService } from '../../settings/theme-settings.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { PerfectScrollbarConfigInterface, PerfectScrollbarComponent, PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
import { MenuSettingsService } from '../../settings/menu-settings.service';
import { isArray } from 'util';
import { trigger, state, style, animate, transition } from '@angular/animations';
import { AppConstants } from 'src/app/_helpers/app.constants';
import { Router, NavigationEnd, Event } from '@angular/router';
@Component({
selector: 'app-verticalnav',
templateUrl: './verticalnav.component.html',
styleUrls: ['./verticalnav.component.css'],
animations: [
trigger('popOverState', [
state('show', style({
opacity: '1',
})),
state('hide', style({
opacity: '0',
height: '*',
})),
transition('show => hide', animate('200ms ease-in-out')),
transition('hide => show', animate('200ms ease-in-out'))
])
]
})
export class VerticalnavComponent implements OnInit {
child: any;
insideTm: any;
outsideTm: any;
loggedInUser: any;
public title;
private _themeSettingsConfig: any;
public _menuSettingsConfig: any;
private _unsubscribeAll: Subject<any>;
private _unsubscribeAllMenu: Subject<any>;
public config: PerfectScrollbarConfigInterface = { wheelPropagation: false };
@ViewChild(PerfectScrollbarComponent) componentRef?: PerfectScrollbarComponent;
@ViewChild(PerfectScrollbarDirective, { static: true }) directiveRef?: PerfectScrollbarDirective;
constructor(
@Inject(DOCUMENT) private document: Document,
private navbarService: NavbarService,
private _themeSettingsService: ThemeSettingsService,
private _menuSettingsService: MenuSettingsService,
private _renderer: Renderer2,
private router: Router
) {
this._unsubscribeAll = new Subject();
this._unsubscribeAllMenu = new Subject();
this.router.events.subscribe((event: Event) => {
if (event instanceof NavigationEnd) {
this.resetMainMenu();
this.setActiveRouteInNavbar();
}
});
}
ngOnInit() {
// Subscribe to config changes
this._themeSettingsService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((config) => {
this._themeSettingsConfig = config;
this.refreshView();
});
this._menuSettingsService.config
.pipe(takeUntil(this._unsubscribeAllMenu))
.subscribe((config) => {
this._menuSettingsConfig = config;
});
// TODO Patch to reset menu after login
this.resetMainMenu();
this.setActiveRouteInNavbar();
}
resetMainMenu() {
const nodes = this.document.getElementById('main-menu-navigation').childNodes;
for (let i = 0; i < nodes.length; i++) {
this.resetCollapseMenu(nodes[i]);
}
for (let i = 0; i < this._menuSettingsConfig.vertical_menu.items.length; i++) {
this._menuSettingsConfig.vertical_menu.items[i]['isSelected'] = false;
this._menuSettingsConfig.vertical_menu.items[i]['hover'] = false;
this._menuSettingsConfig.vertical_menu.items[i]['isOpen'] = false;
this.resetSubmenuItems(this._menuSettingsConfig.vertical_menu.items[i]);
}
}
resetCollapseMenu(element) {
if (element.classList && element.classList.contains('has-sub') && element.classList.contains('open')) {
element.classList.remove('hover');
element.classList.remove('menu-collapsed-open');
}
}
resetSubmenuItems(parentItem) {
if (parentItem['submenu'] &&
parentItem['submenu']['items'] &&
parentItem['submenu']['items'].length > 0) {
parentItem['isOpen'] = false;
for (let j = 0; j < parentItem['submenu']['items'].length; j++) {
parentItem['submenu']['items'][j]['isSelected'] = false;
this.resetSubmenuItems(parentItem['submenu']['items'][j]);
}
}
}
refreshView() {
const mainMenuElement = document.getElementsByClassName('main-menu');
if (mainMenuElement && mainMenuElement.length > 0) {
if (this._themeSettingsConfig.colorTheme === 'semi-light' || this._themeSettingsConfig.colorTheme === 'light') {
this._renderer.removeClass(mainMenuElement.item(0), 'menu-dark');
this._renderer.addClass(mainMenuElement.item(0), 'menu-light');
} else if (this._themeSettingsConfig.colorTheme === 'semi-dark' || this._themeSettingsConfig.colorTheme === 'dark') {
this._renderer.addClass(mainMenuElement.item(0), 'menu-dark');
this._renderer.removeClass(mainMenuElement.item(0), 'menu-light');
}
if (this._themeSettingsConfig.layout.pattern === 'static') {
this._renderer.removeClass(mainMenuElement.item(0), 'menu-fixed');
this._renderer.addClass(mainMenuElement.item(0), 'menu-static');
} else if (this._themeSettingsConfig.layout.pattern === 'fixed') {
this._renderer.removeClass(mainMenuElement.item(0), 'menu-static');
this._renderer.addClass(mainMenuElement.item(0), 'menu-fixed');
}
}
}
setActiveRouteInNavbar() {
for (let i = 0; i < this._menuSettingsConfig.vertical_menu.items.length; i++) {
if (!this._menuSettingsConfig.vertical_menu.items[i].submenu &&
this._menuSettingsConfig.vertical_menu.items[i].page === this.router.url) {
this._menuSettingsConfig.vertical_menu.items[i]['isSelected'] = true;
break;
} else if (this._menuSettingsConfig.vertical_menu.items[i].submenu) {
// Level 1 menu
for (let j = 0; j < this._menuSettingsConfig.vertical_menu.items[i].submenu.items.length; j++) {
if (!this._menuSettingsConfig.vertical_menu.items[i].submenu.items[j].submenu &&
this._menuSettingsConfig.vertical_menu.items[i].submenu.items[j].page === this.router.url) {
this._menuSettingsConfig.vertical_menu.items[i]['isSelected'] = true;
this._menuSettingsConfig.vertical_menu.items[i].submenu.items[j]['isSelected'] = true;
this._menuSettingsConfig.vertical_menu.items[i].isOpen = true;
break;
} else if (this._menuSettingsConfig.vertical_menu.items[i].submenu.items[j].submenu) {
// Level 2 menu
for (let k = 0; k < this._menuSettingsConfig.vertical_menu.items[i].submenu.items[j].submenu.items.length; k++) {
if (this._menuSettingsConfig.vertical_menu.items[i].submenu.items[j].submenu.items[k].page === this.router.url) {
this._menuSettingsConfig.vertical_menu.items[i]['isSelected'] = true;
this._menuSettingsConfig.vertical_menu.items[i].submenu.items[j]['isSelected'] = true;
this._menuSettingsConfig.vertical_menu.items[i].isOpen = true;
this._menuSettingsConfig.vertical_menu.items[i].submenu.items[j]['isSelected'] = true;
this._menuSettingsConfig.vertical_menu.items[i].submenu.items[j].submenu.items[k]['isSelected'] = true;
this._menuSettingsConfig.vertical_menu.items[i].submenu.items[j].isOpen = true;
}
}
} else if(!this._menuSettingsConfig.vertical_menu.items[i].submenu.items[j].submenu ){
let a,b;
let URL = localStorage.getItem('creatorurl');
let SurveyUrl = localStorage.getItem('surveyurl');
if( this._menuSettingsConfig.vertical_menu.items[i].submenu.items[j].page ==='/creator' && this.router.url === URL){
a = j;
this._menuSettingsConfig.vertical_menu.items[i]['isSelected'] = true;
this._menuSettingsConfig.vertical_menu.items[i].submenu.items[a]['isSelected'] = true;
this._menuSettingsConfig.vertical_menu.items[i].isOpen = true;
// this._menuSettingsConfig.vertical_menu.items[i].submenu.items[j]['isSelected'] = false;
} else if(this._menuSettingsConfig.vertical_menu.items[i].submenu.items[j].page ==='/survey' && this.router.url === SurveyUrl){
b = j;
this._menuSettingsConfig.vertical_menu.items[i]['isSelected'] = true;
this._menuSettingsConfig.vertical_menu.items[i].submenu.items[b]['isSelected'] = true;
this._menuSettingsConfig.vertical_menu.items[i].isOpen = true;
if (this._menuSettingsConfig.vertical_menu.items[i].submenu.items[a]) {
this._menuSettingsConfig.vertical_menu.items[i].submenu.items[a]['isSelected'] = false;
}
}
}
}
}
}
}
resetOpenMenu() {
for (let i = 0; i < this._menuSettingsConfig.vertical_menu.items.length; i++) {
const menu = this._menuSettingsConfig.vertical_menu.items[i];
if (!menu.submenu) {
menu['isOpen'] = false;
menu['isActive'] = false;
menu['hover'] = false;
} else if (menu.submenu) {
for (let j = 0; j < menu.submenu.items.length; j++) {
menu['isOpen'] = false;
menu['isActive'] = false;
menu['hover'] = false;
menu.submenu.items[j]['isOpen'] = false;
}
}
}
}
setOpenInNavbar(value) {
for (let i = 0; i < this._menuSettingsConfig.vertical_menu.items.length; i++) {
const menu = this._menuSettingsConfig.vertical_menu.items[i];
if (!menu.submenu &&
menu.page === this.router.url) {
menu['isOpen'] = value;
menu['isActive'] = value;
} else if (menu.submenu) {
for (let j = 0; j < menu.submenu.items.length; j++) {
if (menu.submenu.items[j].page === this.router.url) {
menu['isOpen'] = value;
menu['isActive'] = value;
menu.submenu.items[j]['isOpen'] = value;
menu.submenu.items[j]['isActive'] = value;
break;
}
}
}
}
}
callFunction(event, child, isSubmenuOfSubmenu) {
const methodName = event.methodName;
if (this[methodName]) {
// method exists on the component
const param = event.methodParam;
if (!isArray(param)) {
this[methodName](param); // call it
} else {
this[methodName](param[0], param[1]); // call it
}
}
this.resetOtherActiveMenu(child, isSubmenuOfSubmenu);
child['isSelected'] = true;
}
setTheme(theme) {
this._themeSettingsService.config = {
colorTheme: theme, // semi-light, semi-dark
};
}
setLayout(layout) {
this._themeSettingsService.config = {
layout: {
pattern: layout
}
};
}
fixComponent(component, value) {
if (component === 'header') {
this._themeSettingsService.config = {
header: value
};
} else if (component === 'footer') {
this._themeSettingsService.config = {
footer: value
};
} else {
this._themeSettingsService.config = {
header: value,
footer: value
};
}
}
/**
* Use for fixed left aside menu, to show menu on mouseenter event.
* @param e Event
*/
mouseEnter(e) {
if (this.navbarService.isFixedMenu()) {
return;
}
this.navbarService.setMouseInRegion(true);
const navBar = this.document.getElementById('navbar-header');
const mainMenu = this.document.getElementById('main-menu');
// check if the left aside menu is fixed
if (!navBar.classList.contains('expanded')) {
this._renderer.addClass(navBar, 'expanded');
this._renderer.addClass(mainMenu, 'expanded');
this.resetOpenMenu();
this.setOpenInNavbar(true);
}
}
/**
* Use for fixed left aside menu, to show menu on mouseenter event.
* @param e Event
*/
mouseLeave(event) {
if (this.navbarService.isFixedMenu()) {
return;
}
const _self = this;
const navBar = this.document.getElementById('navbar-header');
const mainMenu = this.document.getElementById('main-menu');
if (navBar && navBar.classList.contains('expanded')) {
this.insideTm = setTimeout(() => {
if (!_self.navbarService.isMouseInRegion()) {
this._renderer.removeClass(navBar, 'expanded');
this._renderer.removeClass(mainMenu, 'expanded');
this.resetOpenMenu();
this.setOpenInNavbar(false);
}
}, 100);
}
this.navbarService.setMouseInRegion(false);
}
resetOtherActiveMenu(selectedChild, isSubmenuOfSubmenu) {
for (let i = 0; i < this._menuSettingsConfig.vertical_menu.items.length; i++) {
this._menuSettingsConfig.vertical_menu.items[i]['isSelected'] = false;
this._menuSettingsConfig.vertical_menu.items[i]['hover'] = false;
this.handleSubmenuItems(this._menuSettingsConfig.vertical_menu.items[i], selectedChild, isSubmenuOfSubmenu);
}
}
handleSubmenuItems(parentItem, selectedChild, isSubmenuOfSubmenu) {
if (selectedChild['title'] === 'Horizontal') {
localStorage.setItem('currentLayoutStyle', AppConstants.LAYOUT_STYLE_HORIZONTAL);
window.location.reload();
} else if (selectedChild['title'] === 'Vertical') {
localStorage.setItem('currentLayoutStyle', AppConstants.LAYOUT_STYLE_VERTICAL);
window.location.reload();
} else if (parentItem['submenu'] &&
parentItem['submenu']['items'] &&
parentItem['submenu']['items'].length > 0) {
if (parentItem.title !== selectedChild.title && parentItem['isOpen'] === true && !isSubmenuOfSubmenu &&
this._themeSettingsConfig.navigation === AppConstants.NAVIGATION_TYPE_COLLAPSIBLE) {
parentItem['isOpen'] = false;
}
for (let j = 0; j < parentItem['submenu']['items'].length; j++) {
if (selectedChild.page !== 'null') {
parentItem['submenu']['items'][j]['isSelected'] = false;
}
this.handleSubmenuItems(parentItem['submenu']['items'][j], selectedChild, isSubmenuOfSubmenu);
}
} else if (parentItem.title !== selectedChild.title && !selectedChild.submenu
&& this._themeSettingsConfig.navigation === AppConstants.NAVIGATION_TYPE_COLLAPSIBLE
&& parentItem['isOpen'] === true) {
parentItem['isOpen'] = false;
}
}
toggleMenu(event, child, isSubmenuOfSubmenu) {
const toggle = document.getElementById('sidenav-overlay');
this.resetOtherActiveMenu(child, isSubmenuOfSubmenu);
this.loggedInUser = JSON.parse(localStorage.getItem('currentUser'));
if (child['isSelected'] === true) {
child['isSelected'] = false;
} else {
child['isSelected'] = true;
}
if (child['hover'] === true) {
child['hover'] = false;
} else {
child['hover'] = true;
}
if (child['isOpen'] === true) {
child['isOpen'] = false;
} else {
child['isOpen'] = true;
}
if (this.router.url !== '') {
this._renderer.addClass(toggle, 'd-none');
this._renderer.removeClass(toggle, 'd-block');
}
if ( child.page === '/chats' && this.loggedInUser.email === 'john@pixinvent.com') {
this.router.navigate(['/chats/static-chat']);
} else if ( child.page === '/chats' && this.loggedInUser.email !== 'john@pixinvent.com') {
this.router.navigate(['/chats']);
}
}
}

View File

@ -0,0 +1,14 @@
<div (window:resize)="onResize($event)"></div>
<app-navigation></app-navigation>
<router-outlet></router-outlet>
<div class="sidenav-overlay d-none" id="sidenav-overlay" (click)="rightbar($event)"></div>
<app-footer></app-footer>
<div *ngIf ="customizer === 'on'">
<app-customizer *ngIf="layout === 'vertical'"></app-customizer>
<app-horizontal-customizer *ngIf="layout === 'horizontal'"></app-horizontal-customizer>
</div>
<div *ngIf ="buybutton === 'on'">
<div class="buy-now" >
<a href="https://1.envato.market/modern_admin_angular" target="_blank" class="btn bg-gradient-directional-purple round white btn-purple btn-glow px-2">Buy Now</a>
</div>
</div>

View File

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

View File

@ -0,0 +1,322 @@
import { Component, OnInit, Renderer2, HostListener, Inject } from '@angular/core';
import { ThemeSettingsService } from '../settings/theme-settings.service';
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { DeviceDetectorService } from '../../_services/device-detector.service';
import { AppConstants } from '../../_helpers/app.constants';
import { Router, NavigationStart, NavigationEnd, Event, NavigationError } from '@angular/router';
import { DOCUMENT } from '@angular/common';
import { NavbarService } from 'src/app/_services/navbar.service';
@Component({
selector: 'app-private-layout',
templateUrl: './private-layout.component.html',
styleUrls: ['./private-layout.component.css']
})
export class PrivateLayoutComponent implements OnInit {
private _unsubscribeAll: Subject<any>;
private _themeSettingsConfig: any;
public layout: any;
public customizer: any;
public buybutton: any;
deviceInfo = null;
constructor(private renderer: Renderer2,
@Inject(DOCUMENT) private document: Document,
private router: Router,
private navbarService: NavbarService,
private _themeSettingsService: ThemeSettingsService,
private deviceService: DeviceDetectorService) {
this._unsubscribeAll = new Subject();
this.router.events.subscribe((event: Event) => {
if (event instanceof NavigationStart) {
// Show loading indicator
}
if (event instanceof NavigationEnd) {
// Hide loading indicator
if (this.router.url === '/chats' || this.router.url === '/chats/static-chat') {
this.renderer.addClass(document.body, 'chat-application');
} else {
this.renderer.removeClass(document.body, 'chat-application');
}
if (this.router.url === '/email') {
this.renderer.addClass(document.body, 'email-application');
} else {
this.renderer.removeClass(document.body, 'email-application');
}
if (this.router.url === '/contacts') {
this.renderer.addClass(document.body, 'app-contacts');
} else {
this.renderer.removeClass(document.body, 'app-contacts');
}
if (this.router.url === '/todos') {
this.renderer.addClass(document.body, 'todo');
} else {
this.renderer.removeClass(document.body, 'todo');
}
if (this.router.url === '/todo-app') {
this.renderer.addClass(document.body, 'todo-application');
} else {
this.renderer.removeClass(document.body, 'todo-application');
}
}
if (event instanceof NavigationError) {
// Hide loading indicator
}
});
}
ngOnInit() {
this.renderer.removeClass(document.body, 'bg-full-screen-image');
// Subscribe to config changes
this._themeSettingsService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((config) => {
this._themeSettingsConfig = config;
if (localStorage.getItem('currentLayoutStyle')) {
this._themeSettingsConfig.layout.style = localStorage.getItem('currentLayoutStyle');
}
});
this.deviceInfo = this.deviceService.getDeviceInfo();
const isMobile = this.deviceService.isMobile();
this.handleBody(isMobile);
this.handleCollapsibleMenu();
}
handleBody(isMobile: boolean) {
const _self = this;
if (this._themeSettingsConfig.layout.style === 'vertical') {
_self.renderer.setAttribute(document.body, 'data-menu', 'vertical-menu-modern');
} else {
_self.renderer.setAttribute(document.body, 'data-menu', 'horizontal-menu-modern');
}
let currentBodyClassList = [];
this.layout = this._themeSettingsConfig.layout.style;
this.customizer = this._themeSettingsConfig.customizer;
this.buybutton = this._themeSettingsConfig.buybutton;
// Vertical resposive view
if (this._themeSettingsConfig.layout.style === 'vertical' &&
window.innerWidth < AppConstants.MOBILE_RESPONSIVE_WIDTH) {
const previosBodyClassList = [].slice.call(document.body.classList);
previosBodyClassList.forEach(function (c) {
_self.renderer.removeClass(document.body, c);
});
if (this._themeSettingsConfig.layout.style === 'vertical') {
currentBodyClassList = ['vertical-layout', 'vertical-overlay-menu', '2-columns', 'pace-done', 'menu-close', 'fixed-navbar'];
if (this._themeSettingsConfig.layout.pattern === 'fixed') {
currentBodyClassList.push('fixed-navbar');
}
} else {
currentBodyClassList = ['vertical-layout', '2-columns', 'vertical-overlay-menu', 'pace-done', 'menu-hide'];
}
if (this._themeSettingsConfig.layout.pattern === 'fixed') {
currentBodyClassList.push('fixed-navbar');
}
if (this._themeSettingsConfig.layout.pattern === '') {
currentBodyClassList.push('fixed-navbar');
}
if (this._themeSettingsConfig.layout.pattern === 'boxed') {
this.renderer.addClass(document.body, 'boxed-layout');
this.renderer.addClass(document.body, 'container');
this.renderer.addClass(document.body, 'fixed-navbar');
}
// Horizontal resposive view
} else if (this._themeSettingsConfig.layout.style === 'horizontal' &&
window.innerWidth < AppConstants.MOBILE_RESPONSIVE_WIDTH_HORIZONTAL) {
const previosBodyClassList = [].slice.call(document.body.classList);
previosBodyClassList.forEach(function (c) {
_self.renderer.removeClass(document.body, c);
});
currentBodyClassList = ['horizontal-layout', 'horizontal-menu', '2-columns', 'pace-done',
'fixed-navbar', 'menu-hide'];
if (this._themeSettingsConfig.layout.pattern === 'fixed') {
currentBodyClassList.push('fixed-navbar');
}
if (this._themeSettingsConfig.layout.pattern === '') {
currentBodyClassList.push('fixed-navbar');
}
if (this._themeSettingsConfig.layout.pattern === 'boxed') {
this.renderer.addClass(document.body, 'boxed-layout');
this.renderer.addClass(document.body, 'container');
this.renderer.addClass(document.body, 'fixed-navbar');
}
// Normal view
} else {
const previosBodyClassList = [].slice.call(document.body.classList);
let callapseOrExpanded = '';
previosBodyClassList.forEach(function (c) {
if (c === 'menu-collapsed') {
callapseOrExpanded = 'menu-collapsed';
} else if (c === 'menu-expanded') {
callapseOrExpanded = 'menu-expanded';
}
_self.renderer.removeClass(document.body, c);
});
if (this._themeSettingsConfig.layout.style === 'vertical') {
if (callapseOrExpanded === '') {
const toggleIcon = document.getElementsByClassName('toggle-icon');
if (toggleIcon.item && toggleIcon.item(0) &&
toggleIcon.item(0).classList.contains('ft-toggle-right')) {
callapseOrExpanded = 'menu-expanded';
} else {
callapseOrExpanded = 'menu-collapsed';
}
}
// callapseOrExpanded = callapseOrExpanded !== '' ? callapseOrExpanded : 'menu-collapsed';
currentBodyClassList = ['vertical-layout', 'vertical-menu-modern', '2-columns', 'pace-done', 'menu-close', callapseOrExpanded];
if (this._themeSettingsConfig.layout.pattern === 'fixed') {
currentBodyClassList.push('fixed-navbar');
}
if (this._themeSettingsConfig.layout.pattern === '') {
currentBodyClassList.push('fixed-navbar');
}
if (this._themeSettingsConfig.layout.pattern === 'boxed') {
this.renderer.addClass(document.body, 'boxed-layout');
this.renderer.addClass(document.body, 'container');
this.renderer.addClass(document.body, 'fixed-navbar');
}
} else {
currentBodyClassList = ['horizontal-layout', '2-columns', 'horizontal-menu'];
if (window.innerWidth >= AppConstants.MOBILE_RESPONSIVE_WIDTH) {
currentBodyClassList.push('menu-expanded');
} else {
currentBodyClassList.push('menu-collapsed');
}
if (this._themeSettingsConfig.layout.pattern === 'boxed') {
this.renderer.addClass(document.body, 'boxed-layout');
this.renderer.addClass(document.body, 'container');
}
}
}
const footer = document.getElementById('footer');
// if (this.router.url == '/chats') {
// const footer = document.getElementById('footer');
if (this.router.url === '/chats' || this.router.url === '/chats/static-chat') {
currentBodyClassList.push('chat-application');
// footer.classList.add('fixed-bottom');
} else if (currentBodyClassList.includes('fixed-bottom')) {
currentBodyClassList.push('chat-application');
currentBodyClassList = currentBodyClassList.filter(item => item !== 'fixed-bottom');
footer.classList.remove('fixed-bottom');
}
if (this.router.url === '/email') {
currentBodyClassList.push('email-application');
// footer.classList.add('fixed-bottom');
} else if (currentBodyClassList.includes('fixed-bottom')) {
currentBodyClassList.push('email-application');
currentBodyClassList = currentBodyClassList.filter(item => item !== 'fixed-bottom');
footer.classList.remove('fixed-bottom');
}
if (this.router.url === '/contacts') {
currentBodyClassList.push('app-contacts');
}
if (this.router.url === '/todos') {
currentBodyClassList.push('todo');
}
if (this.router.url === '/todo-app') {
currentBodyClassList.push('todo-application');
}
currentBodyClassList.forEach(function (c) {
_self.renderer.addClass(document.body, c);
});
this.handleFullScreen();
}
handleFullScreen() {
const toggleIcon = document.getElementsByClassName('ficon');
if (window.innerWidth === screen.width && window.innerHeight === screen.height && toggleIcon.item(0)) {
this.renderer.removeClass(toggleIcon.item(0), 'ft-maximize');
this.renderer.addClass(toggleIcon.item(0), 'ft-minimize');
} else if (toggleIcon.item(0)) {
this.renderer.addClass(toggleIcon.item(0), 'ft-maximize');
this.renderer.removeClass(toggleIcon.item(0), 'ft-minimize');
}
}
handleCollapsibleMenu() {
if (this._themeSettingsConfig.menu === 'collapse') {
// show the left aside menu
this.navbarService.setFixedMenu(false);
this.document.body.classList.remove('menu-expanded');
this.document.body.classList.add('menu-collapsed');
} else {
this.navbarService.setFixedMenu(true);
this.document.body.classList.remove('menu-collapsed');
this.document.body.classList.add('menu-expanded');
}
}
@HostListener('window:resize', ['$event'])
onResize(event) {
const menuClose = document.body.getElementsByClassName('menu-close');
const toggle = document.getElementsByClassName('content-overlay');
const sidenavOverlay = document.getElementsByClassName('sidenav-overlay');
const emailMenu = document.getElementsByClassName('email-app-menu');
const toggleIcon = document.getElementById('sidebar-left');
if (event.target.innerWidth < AppConstants.MOBILE_RESPONSIVE_WIDTH) {
this.handleBody(true);
if (menuClose) {
this.renderer.removeClass(sidenavOverlay.item(0), 'd-block');
this.renderer.addClass(sidenavOverlay.item(0), 'd-none');
}
} else {
this.handleBody(false);
}
if (toggle && (this.router.url === '/chats' || this.router.url === '/static-chat' ||
this.router.url === '/todos' || this.router.url === '/contacts') &&
event.target.innerWidth > AppConstants.MOBILE_RESPONSIVE_WIDTH) {
this.renderer.removeClass(toggle.item(0), 'show');
this.renderer.removeClass(sidenavOverlay.item(0), 'd-block');
this.renderer.addClass(sidenavOverlay.item(0), 'd-none');
this.renderer.removeClass(toggleIcon, 'show');
}
if ((toggle || sidenavOverlay) && this.router.url === '/email' && event.target.innerWidth > 767) {
this.renderer.removeClass(toggle.item(0), 'show');
this.renderer.removeClass(emailMenu.item(0), 'show');
this.renderer.removeClass(sidenavOverlay.item(0), 'd-block');
this.renderer.addClass(sidenavOverlay.item(0), 'd-none');
}
}
rightbar(event) {
const toggle = document.getElementById('sidenav-overlay');
if (event.currentTarget.className === 'sidenav-overlay d-block') {
this.renderer.removeClass(toggle, 'd-block');
this.document.body.classList.remove('menu-open');
this.document.body.classList.add('menu-close');
this.renderer.addClass(toggle, 'd-none');
} else if (event.currentTarget.className === 'sidenav-overlay d-none') {
this.renderer.removeClass(toggle, 'd-none');
this.document.body.classList.remove('menu-close');
this.document.body.classList.add('menu-open');
this.renderer.addClass(toggle, 'd-block');
}
}
}

View File

@ -0,0 +1,2 @@
<router-outlet></router-outlet>
<div class="sidenav-overlay d-none" id="sidenav-overlay" (click)="rightbar($event)"></div>

View File

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

View File

@ -0,0 +1,50 @@
import { Component, OnInit, Renderer2, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { Router, NavigationStart, NavigationEnd, Event, NavigationError } from '@angular/router';
@Component({
selector: 'app-public-layout',
templateUrl: './public-layout.component.html',
styleUrls: ['./public-layout.component.css']
})
export class PublicLayoutComponent implements OnInit {
constructor(private renderer: Renderer2,
private router: Router,
@Inject(DOCUMENT) private document: Document) {}
ngOnInit() {
this.setBodyClass();
}
rightbar(event) {
const toggle = document.getElementById('sidenav-overlay');
if (event.currentTarget.className === 'sidenav-overlay d-block') {
this.renderer.removeClass(toggle, 'd-block');
this.document.body.classList.remove('menu-open');
this.document.body.classList.add('menu-close');
this.renderer.addClass(toggle, 'd-none');
} else if (event.currentTarget.className === 'sidenav-overlay d-none') {
this.renderer.removeClass(toggle, 'd-none');
this.document.body.classList.remove('menu-close');
this.document.body.classList.add('menu-open');
this.renderer.addClass(toggle, 'd-block');
}
}
setBodyClass() {
const previosBodyClassList = [].slice.call(document.body.classList);
const self = this;
previosBodyClassList.forEach(function (c) {
self.renderer.removeClass(document.body, c);
});
const currentBodyClassList = ['vertical-layout', 'bg-full-screen-image', 'vertical-overlay-menu',
'2-columns', 'pace-done', 'menu-close', 'fixed-navbar'];
currentBodyClassList.forEach(function (c) {
self.renderer.addClass(document.body, c);
});
// if (this.router.url === '/login' || (this.router.url === '')) {
// this.renderer.removeClass(document.body, 'fixed-navbar');
// } else {
// this.renderer.addClass(document.body, 'fixed-navbar');
// }
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,60 @@
import { Injectable, InjectionToken, Inject } from '@angular/core';
import { Router, RoutesRecognized } from '@angular/router';
import { BehaviorSubject, Observable } from 'rxjs';
import { filter } from 'rxjs/operators';
import * as _ from 'lodash';
export const MENU_SETTINGS_CONFIG = new InjectionToken('menuCustomConfig');
@Injectable({
providedIn: 'root'
})
export class MenuSettingsService {
private _configSubject: BehaviorSubject<any>;
private readonly _defaultConfig: any;
constructor(private _router: Router, @Inject(MENU_SETTINGS_CONFIG) private _config) {
// Set the default config from the user provided config (from forRoot)
this._defaultConfig = _config;
// Initialize the service
this._init();
}
private _init(): void {
// Set the config from the default config
this._configSubject = new BehaviorSubject(_.cloneDeep(this._defaultConfig));
// Reload the default layout config on every RoutesRecognized event
// if the current layout config is different from the default one
this._router.events
.pipe(filter(event => event instanceof RoutesRecognized))
.subscribe(() => {
if (!_.isEqual(this._configSubject.getValue().layout, this._defaultConfig.layout)) {
// Clone the current config
const config = _.cloneDeep(this._configSubject.getValue());
// Set the config
this._configSubject.next(config);
}
});
}
set config(value) {
// Get the value from the behavior subject
let config = this._configSubject.getValue();
// Merge the new config
config = _.merge({}, config, value);
// Notify the observers
this._configSubject.next(config);
}
get config(): any | Observable<any> {
return this._configSubject.asObservable();
}
}

View File

@ -0,0 +1,28 @@
import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';
import { THEME_SETTINGS_CONFIG } from './theme-settings.service';
import { MENU_SETTINGS_CONFIG } from './menu-settings.service';
@NgModule()
export class SettingsModule {
constructor(@Optional() @SkipSelf() parentModule: SettingsModule) {
if (parentModule) {
throw new Error('SettingsModule is already loaded. Import it in the AppModule only!');
}
}
static forRoot(themeConfig, menuConfig): ModuleWithProviders<SettingsModule> {
return {
ngModule: SettingsModule,
providers: [
{
provide: THEME_SETTINGS_CONFIG,
useValue: themeConfig
},
{
provide: MENU_SETTINGS_CONFIG,
useValue: menuConfig
}
]
};
}
}

View File

@ -0,0 +1,33 @@
// Default theme settings configurations
export const ThemeSettingsConfig = {
colorTheme: 'semi-dark', // light, semi-light, semi-dark, dark
layout: {
style: 'vertical', // style: 'vertical', horizontal,
pattern: 'fixed' // fixed, boxed, static
},
menuColor: 'menu-dark', // Vertical: [menu-dark, menu-light] , Horizontal: [navbar-dark, navbar-light]
navigation: 'menu-collapsible', // menu-collapsible, menu-accordation
menu: 'expand', // collapse, expand
header: 'fix', // fix, static
footer: 'static', // fix, static
customizer: 'on', // on,off
buybutton: 'on', // on, off
headerIcons: {
maximize: 'on', // on, off
search: 'on', // on, off
internationalization: 'on', // on, off
notification: 'on', // on, off
email: 'on' // on, off
},
brand: {
brand_name: 'Modern ',
logo: {
type: 'internal', // internal, url
value: 'assets/custom/images/logo.png' // recommended location for custom images
// type:'url',
// value:'http://evolvision.com/wp-content/uploads/2018/01/envelope4-green.png'
},
},
defaultTitleSuffix: 'Modern Admin - Angular 11+ Bootstrap 5 Admin Dashboard Template'
};

View File

@ -0,0 +1,63 @@
import { Injectable, InjectionToken, Inject } from '@angular/core';
import { Router, RoutesRecognized } from '@angular/router';
import { BehaviorSubject, Observable } from 'rxjs';
import { filter } from 'rxjs/operators';
import * as _ from 'lodash';
export const THEME_SETTINGS_CONFIG = new InjectionToken('themeCustomConfig');
@Injectable({
providedIn: 'root'
})
export class ThemeSettingsService {
// Private
private _configSubject: BehaviorSubject<any>;
private readonly _defaultConfig: any;
constructor(private _router: Router, @Inject(THEME_SETTINGS_CONFIG) private _config) {
// Set the default config from the user provided config (from forRoot)
this._defaultConfig = _config;
// Initialize the service
this._init();
}
private _init(): void {
// Set the config from the default config
this._configSubject = new BehaviorSubject(_.cloneDeep(this._defaultConfig));
// Reload the default layout config on every RoutesRecognized event
// if the current layout config is different from the default one
this._router.events
.pipe(filter(event => event instanceof RoutesRecognized))
.subscribe(() => {
if (!_.isEqual(this._configSubject.getValue().layout, this._defaultConfig.layout)) {
// Clone the current config
const config = _.cloneDeep(this._configSubject.getValue());
// Reset the layout from the default config
// config.layout = _.cloneDeep(this._defaultConfig.layout);
// Set the config
this._configSubject.next(config);
}
});
}
set config(value) {
// Get the value from the behavior subject
let config = this._configSubject.getValue();
// Merge the new config
config = _.merge({}, config, value);
// Notify the observers
this._configSubject.next(config);
}
get config(): any | Observable<any> {
return this._configSubject.asObservable();
}
}

View File

@ -0,0 +1,38 @@
import { Injectable } from '@angular/core';
import { Router, NavigationStart } from '@angular/router';
import { Observable, Subject } from 'rxjs';
@Injectable()
export class AlertService {
private subject = new Subject<any>();
private keepAfterNavigationChange = false;
constructor(private router: Router) {
// Clear alert message on route change
router.events.subscribe(event => {
if (event instanceof NavigationStart) {
if (this.keepAfterNavigationChange) {
// Only keep for a single location change
this.keepAfterNavigationChange = false;
} else {
// Clear alert
this.subject.next({});
}
}
});
}
success(message: string, keepAfterNavigationChange = false) {
this.keepAfterNavigationChange = keepAfterNavigationChange;
this.subject.next({ type: 'success', text: message });
}
error(message: string, keepAfterNavigationChange = false) {
this.keepAfterNavigationChange = keepAfterNavigationChange;
this.subject.next({ type: 'error', text: message });
}
getMessage(): Observable<any> {
return this.subject.asObservable();
}
}

View File

@ -0,0 +1,12 @@
import { TestBed } from '@angular/core/testing';
import { ApplicationApiService } from './application-api.service';
describe('ApplicationApiService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: ApplicationApiService = TestBed.get(ApplicationApiService);
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,49 @@
import { Injectable } from '@angular/core';
import { Observable, of, throwError } from 'rxjs';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
@Injectable({
providedIn: 'root'
})
export class ApplicationApiService {
apiBaseURL = 'assets/data';
loadChatsDataURL = null;
loadEmailDataURL = null;
loadChatContactDataURL = null;
constructor(private http: HttpClient) {
this.loadChatsDataURL = `${this.apiBaseURL}/application/chats.json`;
this.loadChatContactDataURL = `${this.apiBaseURL}/application/chatcontact.json`;
this.loadEmailDataURL = `${this.apiBaseURL}/application/email.json`;
}
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// Error
console.error('error:', error.error.message);
} else {
// Error
console.error(
`Api server returned ${error.status}, ` +
`error body: ${error.error}`);
}
// throwError is observable
return throwError('Error has happened');
}
private extractData(res: Response) {
const body = res;
return body || {};
}
getChatsData(): Observable<any> {
return this.http.get(this.loadChatsDataURL, httpOptions);
}
getChatContactData(): Observable<any> {
return this.http.get(this.loadChatContactDataURL, httpOptions);
}
getEmailData(): Observable<any> {
return this.http.get(this.loadEmailDataURL, httpOptions);
}
}

View File

@ -0,0 +1,120 @@
import { Injectable } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/compat/auth';
import firebase from 'firebase/compat/app';
@Injectable()
export class AuthService {
constructor(public afAuth: AngularFireAuth) {}
// Facebook login
doFacebookLogin() {
return new Promise<any>((resolve, reject) => {
const provider = new firebase.auth.FacebookAuthProvider();
this.afAuth.signInWithPopup(provider).then(
res => {
resolve(res);
},
err => {
console.log(err);
reject(err);
}
);
});
}
// Github login
doGitHubLogin() {
return new Promise<any>((resolve, reject) => {
const provider = new firebase.auth.GithubAuthProvider();
this.afAuth.signInWithPopup(provider).then(
res => {
resolve(res);
},
err => {
console.log(err);
reject(err);
}
);
});
}
// Twitter login
doTwitterLogin() {
return new Promise<any>((resolve, reject) => {
const provider = new firebase.auth.TwitterAuthProvider();
this.afAuth.signInWithPopup(provider).then(
res => {
resolve(res);
},
err => {
console.log(err);
reject(err);
}
);
});
}
// Google login
doGoogleLogin() {
return new Promise<any>((resolve, reject) => {
const provider = new firebase.auth.GoogleAuthProvider();
provider.addScope('profile');
provider.addScope('email');
this.afAuth.signInWithPopup(provider).then(
res => {
resolve(res);
},
err => {
console.log(err);
reject(err);
}
);
});
}
// Register
doRegister(value) {
return new Promise<any>((resolve, reject) => {
firebase
.auth()
.createUserWithEmailAndPassword(value.email, value.password)
.then(
res => {
resolve(res);
},
err => reject(err)
);
});
}
// Login
doLogin(value) {
return new Promise<any>((resolve, reject) => {
firebase
.auth()
.signInWithEmailAndPassword(value.email, value.password)
.then(
res => {
resolve(res);
},
err => reject(err)
);
});
}
// Logout
doLogout() {
return new Promise<void>((resolve, reject) => {
if (firebase.auth().currentUser) {
localStorage.removeItem('currentUser');
localStorage.removeItem('remember');
this.afAuth.signOut();
resolve();
} else {
localStorage.removeItem('currentUser');
resolve();
}
});
}
}

View File

@ -0,0 +1,66 @@
import { Injectable } from '@angular/core';
import { Observable, of, throwError } from 'rxjs';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { catchError, tap, map } from 'rxjs/operators';
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
@Injectable()
export class ChartApiService {
apiBaseURL = 'assets/data';
loadDataURL = null;
loadSalesDataURL = null;
loadEcommerceDataURL = null;
loadStatisticsDataURL = null;
loadTimelineDataURL = null;
loadInvoiceDataURL = null;
constructor(private http: HttpClient) {
this.loadDataURL = `${this.apiBaseURL}/chartist/charts/chartist.json`;
this.loadSalesDataURL = `${this.apiBaseURL}/dashboard/sales/chartist.json`;
this.loadEcommerceDataURL = `${this.apiBaseURL}/dashboard/ecommerce/chartist.json`;
this.loadStatisticsDataURL = `${this.apiBaseURL}/advancecard/statistics/chartist.json`;
this.loadStatisticsDataURL = `${this.apiBaseURL}/advancecard/statistics/chartist.json`;
this.loadTimelineDataURL = `${this.apiBaseURL}/user-profile/user-profile.json`;
this.loadInvoiceDataURL = `${this.apiBaseURL}/invoice-summary/invoice-summary.json`;
}
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// Error
console.error('error:', error.error.message);
} else {
// Error
console.error(
`Api server returned ${error.status}, ` +
`error body: ${error.error}`);
}
// throwError is observable
return throwError('Error has happened');
}
private extractData(res: Response) {
const body = res;
return body || {};
}
getChartistData(): Observable<any> {
return this.http.get(this.loadDataURL, httpOptions);
}
getSalesData(): Observable<any> {
return this.http.get(this.loadSalesDataURL, httpOptions);
}
getEcommerceData(): Observable<any> {
return this.http.get(this.loadEcommerceDataURL, httpOptions);
}
getStatisticsData(): Observable<any> {
return this.http.get(this.loadStatisticsDataURL, httpOptions);
}
getTimelineData(): Observable<any> {
return this.http.get(this.loadTimelineDataURL, httpOptions);
}
getInvoiceData(): Observable<any> {
return this.http.get(this.loadInvoiceDataURL, httpOptions);
}
}

Some files were not shown because too many files have changed in this diff Show More