first commit

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

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);
}
}

View File

@@ -0,0 +1,105 @@
import {Injectable, PipeTransform} from '@angular/core';
import {BehaviorSubject, Observable, of, Subject} from 'rxjs';
import {COUNTRIES, Country} from '../content/table/boostraptables/ngxboostraptables/countries';
import {DecimalPipe} from '@angular/common';
import {debounceTime, delay, switchMap, tap} from 'rxjs/operators';
import {SortDirection} from '../_directives/sortable.directive';
interface SearchResult {
countries: Country[];
total: number;
}
interface State {
page: number;
pageSize: number;
searchTerm: string;
sortColumn: string;
sortDirection: SortDirection;
}
function compare(v1, v2) {
return v1 < v2 ? -1 : v1 > v2 ? 1 : 0;
}
function sort(countries: Country[], column: string, direction: string): Country[] {
if (direction === '') {
return countries;
} else {
return [...countries].sort((a, b) => {
const res = compare(a[column], b[column]);
return direction === 'asc' ? res : -res;
});
}
}
function matches(country: Country, term: string, pipe: PipeTransform) {
return country.firstname.toLowerCase().includes(term.toLowerCase())
|| country.lastname.toLowerCase().includes(term.toLowerCase())
|| country.username.toLowerCase().includes(term.toLowerCase());
}
@Injectable({providedIn: 'root'})
export class CountryService {
private _loading$ = new BehaviorSubject<boolean>(true);
private _search$ = new Subject<void>();
private _countries$ = new BehaviorSubject<Country[]>([]);
private _total$ = new BehaviorSubject<number>(0);
private _state: State = {
page: 1,
pageSize: 4,
searchTerm: '',
sortColumn: '',
sortDirection: ''
};
constructor(private pipe: DecimalPipe) {
this._search$.pipe(
tap(() => this._loading$.next(true)),
debounceTime(200),
switchMap(() => this._search()),
delay(200),
tap(() => this._loading$.next(false))
).subscribe(result => {
this._countries$.next(result.countries);
this._total$.next(result.total);
});
this._search$.next();
}
get countries$() { return this._countries$.asObservable(); }
get total$() { return this._total$.asObservable(); }
get loading$() { return this._loading$.asObservable(); }
get page() { return this._state.page; }
get pageSize() { return this._state.pageSize; }
get searchTerm() { return this._state.searchTerm; }
set page(page: number) { this._set({page}); }
set pageSize(pageSize: number) { this._set({pageSize}); }
set searchTerm(searchTerm: string) { this._set({searchTerm}); }
set sortColumn(sortColumn: string) { this._set({sortColumn}); }
set sortDirection(sortDirection: SortDirection) { this._set({sortDirection}); }
private _set(patch: Partial<State>) {
Object.assign(this._state, patch);
this._search$.next();
}
private _search(): Observable<SearchResult> {
const {sortColumn, sortDirection, pageSize, page, searchTerm} = this._state;
// 1. sort
let countries = sort(COUNTRIES, sortColumn, sortDirection);
// 2. filter
countries = countries.filter(country => matches(country, searchTerm, this.pipe));
const total = countries.length;
// 3. paginate
countries = countries.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize);
return of({countries, total});
}
}

View File

@@ -0,0 +1,86 @@
import { PLATFORM_ID, Inject , Injectable} from '@angular/core'
import { isPlatformBrowser } from '@angular/common'
import { DeviceInfo, DevicePlatform, DeviceOs, DeviceMobile, DeviceTablet } from './device-detector'
@Injectable({
providedIn: 'root'
})
export class DeviceDetectorService {
userAgent: string
constructor(@Inject(PLATFORM_ID) private platformId) {
this.userAgent = isPlatformBrowser(this.platformId) ? window.navigator.userAgent.toLowerCase() : ''
}
private find(match) {
return this.userAgent.indexOf(match) !== -1
}
private findMatch(type) {
return Object.entries(type).find(([key, val]) => !!val) || []
}
private deviceOS() {
const isWindows = this.find('windows')
const isIos = this.deviceShared()[DeviceMobile.Iphone] || this.deviceShared()[DeviceTablet.Ipad]
return {
[DeviceOs.Windows]: isWindows,
[DeviceOs.Macos]: !isIos && this.find('mac'),
[DeviceOs.Android]: !isWindows && this.find('android'),
[DeviceOs.Ios]: isIos,
[DeviceOs.Blackberry]: this.find('blackberry') || this.find('bb10'),
[DeviceOs.Fxos]: (this.find('(mobile') || this.find('(tablet')) && this.find(' rv:')
}
}
private deviceShared() {
return {
[DeviceMobile.Iphone]: !this.find('windows') && this.find('iphone'),
[DeviceTablet.Ipad]: this.find('ipad') || navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1,
}
}
private deviceMobile() {
return {
[DeviceMobile.Iphone]: this.deviceShared()[DeviceMobile.Iphone],
[DeviceMobile.AndroidPhone]: this.deviceOS()[DeviceOs.Android] && this.find('mobile'),
[DeviceMobile.WindowsPhone]: this.deviceOS()[DeviceOs.Windows] && this.find('phone'),
[DeviceMobile.BlackberryPhone]: this.deviceOS()[DeviceOs.Blackberry] && !this.find('tablet'),
[DeviceMobile.Meego]: this.find('meego'),
[DeviceMobile.FxosPhone]: this.deviceOS()[DeviceOs.Fxos] && this.find('mobile')
}
}
private deviceTablet() {
return {
[DeviceTablet.Ipad]: this.deviceShared()[DeviceTablet.Ipad],
[DeviceTablet.AndroidTablet]: this.deviceOS()[DeviceOs.Android] && !this.find('mobile'),
[DeviceTablet.BlackberryTablet]: this.deviceOS()[DeviceOs.Blackberry] && this.find('tablet'),
[DeviceTablet.WindowsTablet]: this.deviceOS()[DeviceOs.Windows] && (this.find('touch') && !this.deviceMobile()[DeviceMobile.WindowsPhone]),
[DeviceTablet.FxosTablet]: this.deviceOS()[DeviceOs.Fxos] && this.find('tablet'),
}
}
isMobile() {
return this.findMatch(this.deviceMobile()).length > 0
}
isTablet() {
return this.findMatch(this.deviceTablet()).length > 0
}
isDesktop() {
return !this.isTablet() && !this.isMobile()
}
getDeviceInfo(): DeviceInfo {
const touchDevices = this.findMatch({ ...this.deviceMobile(), ...this.deviceTablet() })
return {
platform: this.isDesktop() ? DevicePlatform.Desktop : (this.isMobile() ? DevicePlatform.Mobile : DevicePlatform.Tablet),
os: this.findMatch(this.deviceOS())[0],
device: touchDevices.length ? touchDevices[0] : DevicePlatform.Desktop
}
}
}

View File

@@ -0,0 +1,38 @@
export enum DevicePlatform {
Mobile = 'mobile',
Tablet = 'tablet',
Desktop = 'desktop'
}
export enum DeviceOs {
Ios = 'ios',
Android = 'android',
Macos = 'macos',
Windows = 'windows',
Blackberry = 'blackberry',
Fxos = 'fxos'
}
export enum DeviceMobile {
AndroidPhone = 'androidPhone',
Iphone = 'iphone',
WindowsPhone = 'windowsPhone',
BlackberryPhone = 'blackberryPhone',
Meego = 'meego',
FxosPhone = 'fxosPhone'
}
export enum DeviceTablet {
Ipad = 'ipad',
AndroidTablet = 'androidTablet',
BlackberryTablet = 'blackberryTablet',
WindowsTablet = 'windowsTablet',
FxosTablet = 'fxosTablet'
}
export interface DeviceInfo {
platform: DevicePlatform
os: DeviceOs | string
device: DeviceMobile | DeviceTablet | string
}

View File

@@ -0,0 +1,56 @@
import { Injectable } from '@angular/core';
import { MapsAPILoader } from '@agm/core';
import { from } from 'rxjs';
import { tap, map, switchMap } from 'rxjs/operators';
import { Observable, of } from 'rxjs';
import { Location } from '../content/maps/services/services.component';
declare var google: any;
@Injectable({
providedIn: 'root'
})
export class GeocodingService {
private geocoder: any;
constructor(private mapLoader: MapsAPILoader) {}
private initGeocoder() {
console.log('Init geocoder!');
this.geocoder = new google.maps.Geocoder();
}
private waitForMapsToLoad(): Observable<boolean> {
if (!this.geocoder) {
return from(this.mapLoader.load()).pipe(
tap(() => this.initGeocoder()),
map(() => true)
);
}
return of(true);
}
geocodeAddress(location: string): Observable<Location> {
console.log('Start geocoding!');
return this.waitForMapsToLoad().pipe(
// filter(loaded => loaded),
switchMap(() => {
return new Observable<Location>(observer => {
this.geocoder.geocode({ address: location }, (results, status) => {
if (status === google.maps.GeocoderStatus.OK) {
console.log('Geocoding complete!');
observer.next({
lat: results[0].geometry.location.lat(),
lng: results[0].geometry.location.lng()
});
} else {
console.log('Error - ', results, ' & Status - ', status);
observer.next({ lat: 0, lng: 0 });
}
observer.complete();
});
});
})
);
}
}

View File

@@ -0,0 +1,24 @@
import { Injectable } from "@angular/core";
@Injectable()
export class NavbarService {
private mouseInMenuRegion = false;
private fixedMenu = false;
constructor() {}
isMouseInRegion() {
return this.mouseInMenuRegion;
}
setMouseInRegion(flag) {
this.mouseInMenuRegion = flag;
}
isFixedMenu() {
return this.fixedMenu;
}
setFixedMenu(flag) {
this.fixedMenu = flag;
}
}

View File

@@ -0,0 +1,37 @@
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { delay } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';
export interface City {
item_id: number;
item_text: string;
}
@Injectable({
providedIn: 'root'
})
export class NgSelectDataService {
constructor(private http: HttpClient) { }
getPeople(term: string = null): Observable<City[]> {
let items = getMockCity();
if (term) {
items = items.filter(x => x.item_text.toLocaleLowerCase().indexOf(term.toLocaleLowerCase()) > -1);
}
return of(items).pipe(delay(500));
}
}
function getMockCity() {
return [
{ item_id: 1, item_text: 'Alaska' },
{ item_id: 2, item_text: 'California' },
{ item_id: 3, item_text: 'Colorado' },
{ item_id: 4, item_text: 'New Mexico' },
{ item_id: 5, item_text: 'Alabama' },
{ item_id: 6, item_text: 'Connecticut' },
{ item_id: 7, item_text: 'New York' }
];
}

View File

@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { QuillInitializeServiceService } from './quill-initialize-service.service';
describe('QuillInitializeServiceService', () => {
let service: QuillInitializeServiceService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(QuillInitializeServiceService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@@ -0,0 +1,20 @@
import { Injectable } from '@angular/core';
import Quill from 'quill';
import QuillAutoLink from '../content/applications/quill/quillAutolinks';
@Injectable({
providedIn: 'root'
})
export class QuillInitializeServiceService {
constructor() {
var Link = Quill.import('formats/link');
Link.sanitize = (url) => {
if(url.indexOf("http") <= -1){
url = "https://" + url;
}
return url;
}
Quill.register('modules/autoLink', QuillAutoLink);
}
}

View File

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

View File

@@ -0,0 +1,99 @@
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({
providedIn: 'root'
})
export class TableApiService {
apiBaseURL = 'assets/data';
loadEcommerceTableDataURL = null;
loadInvoiceTableDataURL = null;
loadBasicTableDataURL = null;
loadTableBorderDataURL = null;
loadTableStylingDataURL = null;
loadTableApiDataURL = null;
loadTableInitialisationDataURL = null;
loadStylingDataURL = null;
loadTableButtonDataURL = null;
loadTableExportDataURL = null;
loadTableHiddenDataURL = null;
loadTableNgxDataURL = null;
constructor(private http: HttpClient) {
this.loadEcommerceTableDataURL = `${this.apiBaseURL}/dashboard/ecommerce/datatable.json`;
this.loadInvoiceTableDataURL = `${this.apiBaseURL}/invoice/invoicelist/invoicetable.json`;
this.loadBasicTableDataURL = `${this.apiBaseURL}/boostraptable/basictable.json`;
this.loadTableBorderDataURL = `${this.apiBaseURL}/boostraptable/tableborder.json`;
this.loadTableStylingDataURL = `${this.apiBaseURL}/boostraptable/tablestyling.json`;
this.loadTableApiDataURL = `${this.apiBaseURL}/datatables/tableapi/tableapi.json`;
this.loadTableInitialisationDataURL = `${this.apiBaseURL}/datatables/tableinitialisation/tableinitialisation.json`;
this.loadStylingDataURL = `${this.apiBaseURL}/datatables/tablestyling/tablestyling.json`;
this.loadTableButtonDataURL = `${this.apiBaseURL}/datatables/buttons/tablebuttons.json`;
this.loadTableExportDataURL = `${this.apiBaseURL}/datatables/html5dataexport/html5dataexport.json`;
this.loadTableHiddenDataURL = `${this.apiBaseURL}/datatables/hiddentable/hiddentable.json`;
this.loadTableNgxDataURL = `${this.apiBaseURL}/boostraptable/ngxboostraptables.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 || {};
}
getEcommerceTableData(): Observable<any> {
return this.http.get(this.loadEcommerceTableDataURL, httpOptions);
}
getInvoiceTableData(): Observable<any> {
return this.http.get(this.loadInvoiceTableDataURL, httpOptions);
}
getBasicTableData(): Observable<any> {
return this.http.get(this.loadBasicTableDataURL, httpOptions);
}
getTableBorderData(): Observable<any> {
return this.http.get(this.loadTableBorderDataURL, httpOptions);
}
getTableStylingData(): Observable<any> {
return this.http.get(this.loadTableStylingDataURL, httpOptions);
}
getTableApiData(): Observable<any> {
return this.http.get(this.loadTableApiDataURL, httpOptions);
}
getTableInitialisationData(): Observable<any> {
return this.http.get(this.loadTableInitialisationDataURL, httpOptions);
}
getStylingData(): Observable<any> {
return this.http.get(this.loadStylingDataURL, httpOptions);
}
getTableButtonData(): Observable<any> {
return this.http.get(this.loadTableButtonDataURL, httpOptions);
}
getTableExportData(): Observable<any> {
return this.http.get(this.loadTableExportDataURL, httpOptions);
}
getTableHiddenData(): Observable<any> {
return this.http.get(this.loadTableHiddenDataURL, httpOptions);
}
getTableNgxData(): Observable<any> {
return this.http.get(this.loadTableNgxDataURL, httpOptions);
}
}

View File

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

View File

@@ -0,0 +1,37 @@
import { Injectable } from '@angular/core';
import * as FileSaver from 'file-saver';
import * as XLSX from 'xlsx';
const EXCEL_TYPE =
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8';
const EXCEL_EXTENSION = '.xlsx';
@Injectable({
providedIn: 'root'
})
export class TableexcelService {
constructor() { }
public exportAsExcelFile(json: any[], excelFileName: string): void {
const worksheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(json);
console.log('worksheet', worksheet);
const workbook: XLSX.WorkBook = {
Sheets: { data: worksheet },
SheetNames: ['data']
};
const excelBuffer: any = XLSX.write(workbook, {
bookType: 'xlsx',
type: 'array'
});
this.saveAsExcelFile(excelBuffer, excelFileName);
}
private saveAsExcelFile(buffer: any, fileName: string): void {
const data: Blob = new Blob([buffer], {
type: EXCEL_TYPE
});
FileSaver.saveAs(
data,
fileName + '_export_' + new Date().getTime() + EXCEL_EXTENSION
);
}
}

View File

View File

@@ -0,0 +1,4 @@
<!-- main app container -->
<ngx-loading-bar [includeSpinner]='false' height='3px' color="#FF4961"></ngx-loading-bar>
<app-alert></app-alert>
<router-outlet *ngIf="showContent"></router-outlet>

View File

@@ -0,0 +1,27 @@
import { TestBed, waitForAsync } from '@angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the app', waitForAsync(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it(`should have as title 'modern-admin'`, waitForAsync(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('modern-admin');
}));
it('should render title in a h1 tag', waitForAsync(() => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Welcome to modern-admin!');
}));
});

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