Add project files.

This commit is contained in:
2023-04-29 09:17:17 +03:00
commit 62178f1f32
493 changed files with 45863 additions and 0 deletions
@@ -0,0 +1,3 @@
<div [dir]="direction">
<router-outlet></router-outlet>
</div>
@@ -0,0 +1,59 @@
import { Direction } from '@angular/cdk/bidi';
import { Component, Inject, Renderer2 } from '@angular/core';
import { InConfiguration } from 'src/app/core/models/config.interface';
import { DirectionService } from 'src/app/core/service/direction.service';
import { ConfigService } from 'src/app/config/config.service';
import { DOCUMENT } from '@angular/common';
@Component({
selector: 'app-auth-layout',
templateUrl: './auth-layout.component.html',
styleUrls: [],
})
export class AuthLayoutComponent {
direction!: Direction;
config!: InConfiguration;
constructor(
@Inject(DOCUMENT) private document: Document,
private directoryService: DirectionService,
private configService: ConfigService,
private renderer: Renderer2
) {
this.config = this.configService.configData;
this.directoryService.currentData.subscribe((currentData) => {
if (currentData) {
this.direction = currentData === 'ltr' ? 'ltr' : 'rtl';
} else {
if (localStorage.getItem('isRtl')) {
if (localStorage.getItem('isRtl') === 'true') {
this.direction = 'rtl';
} else if (localStorage.getItem('isRtl') === 'false') {
this.direction = 'ltr';
}
} else {
if (this.config) {
if (this.config.layout.rtl === true) {
this.direction = 'rtl';
localStorage.setItem('isRtl', 'true');
} else {
this.direction = 'ltr';
localStorage.setItem('isRtl', 'false');
}
}
}
}
});
// set theme on startup
if (localStorage.getItem('theme')) {
this.renderer.removeClass(this.document.body, this.config.layout.variant);
this.renderer.addClass(
this.document.body,
localStorage.getItem('theme') as string
);
} else {
this.renderer.addClass(this.document.body, this.config.layout.variant);
}
}
}
@@ -0,0 +1,6 @@
<app-header></app-header>
<app-sidebar></app-sidebar>
<app-right-sidebar></app-right-sidebar>
<div [dir]="direction">
<router-outlet></router-outlet>
</div>
@@ -0,0 +1,45 @@
import { Direction } from '@angular/cdk/bidi';
import { Component } from '@angular/core';
import { InConfiguration } from 'src/app/core/models/config.interface';
import { DirectionService } from 'src/app/core/service/direction.service';
import { ConfigService } from 'src/app/config/config.service';
@Component({
selector: 'app-main-layout',
templateUrl: './main-layout.component.html',
styleUrls: [],
})
export class MainLayoutComponent {
direction!: Direction;
config!: InConfiguration;
constructor(
private directoryService: DirectionService,
private configService: ConfigService
) {
this.config = this.configService.configData;
this.directoryService.currentData.subscribe((currentData) => {
if (currentData) {
this.direction = currentData === 'ltr' ? 'ltr' : 'rtl';
} else {
if (localStorage.getItem('isRtl')) {
if (localStorage.getItem('isRtl') === 'true') {
this.direction = 'rtl';
} else if (localStorage.getItem('isRtl') === 'false') {
this.direction = 'ltr';
}
} else {
if (this.config) {
if (this.config.layout.rtl === true) {
this.direction = 'rtl';
localStorage.setItem('isRtl', 'true');
} else {
this.direction = 'ltr';
localStorage.setItem('isRtl', 'false');
}
}
}
}
});
}
}
@@ -0,0 +1,179 @@
<nav #navbar class="navbar active">
<div class="container-fluid">
<div class="collapse navbar-collapse">
<ul class="float-start collapse-menu-icon">
<li>
<button mat-button (click)="mobileMenuSidebarOpen($event,'overlay-open')" class="sidemenu-collapse">
<app-feather-icons [icon]="'menu'" [class]="'header-icon'"></app-feather-icons>
</button>
</li>
</ul>
<ul class="float-start navbar-nav navbar-left">
<li class="nav-item btnAppList" ngbDropdown>
<button mat-button [matMenuTriggerFor]="appDropdownMenu" class="nav-notification-icons">
<app-feather-icons [icon]="'grid'" [class]="'header-icon'"></app-feather-icons>
</button>
<mat-menu #appDropdownMenu="matMenu" class="notification-dropdown app-dropdown" xPosition="before">
<div class="noti-list">
<ul class="menu">
<li class="nfc-header">
<h5 class="mb-0">Applications</h5>
</li>
<li>
<div class="row g-0 p-1">
<div class="col-3 text-center">
<a routerLink="/apps/chat" class="app-icons">
<img src="assets/images/apps/chat.png">
<p class="tx-12 mb-0">Chat</p>
</a>
</div>
<div class="col-3 text-center">
<a routerLink="/calendar" class="app-icons">
<img src="assets/images/apps/calendar.png">
<p class="tx-12 mb-0">Calendar</p>
</a>
</div>
<div class="col-3 text-center">
<a routerLink="/task" class="app-icons">
<img src="assets/images/apps/task.png">
<p class="tx-12 mb-0">Task</p>
</a>
</div>
<div class="col-3 text-center">
<a routerLink="/email/inbox" class="app-icons">
<img src="assets/images/apps/mail.png">
<p class="tx-12 mb-0">Mail</p>
</a>
</div>
</div>
<div class="row g-0 p-1">
<div class="col-3 text-center">
<a routerLink="/contacts" class="app-icons">
<img src="assets/images/apps/contact.png">
<p class="tx-12 mb-0">Contact</p>
</a>
</div>
<div class="col-3 text-center">
<a routerLink="/apps/support" class="app-icons">
<img src="assets/images/apps/support.png">
<p class="tx-12 mb-0">Support</p>
</a>
</div>
<div class="col-3 text-center">
<a routerLink="/media/gallery" class="app-icons">
<img src="assets/images/apps/gallery.png">
<p class="tx-12 mb-0">Gallery</p>
</a>
</div>
</div>
</li>
</ul>
</div>
</mat-menu>
</li>
</ul>
</div>
<div class="collapse navbar-collapse" [ngClass]="isNavbarCollapsed ? '' : 'show'">
<ul class="nav navbar-nav navbar-right">
<!-- Full Screen Button -->
<li class="fullscreen">
<button mat-button class="nav-notification-icons" (click)="callFullscreen()">
<app-feather-icons [icon]="'maximize'" [class]="'header-icon'"></app-feather-icons>
</button>
</li>
<!-- #END# Full Screen Button -->
<li class="nav-item">
<button mat-button [matMenuTriggerFor]="languagemenu" class="lang-dropdown nav-notification-icons">
<img *ngIf="flagvalue !== undefined" src="{{flagvalue}}" height="16">
<img *ngIf="flagvalue === undefined" src="{{defaultFlag}}" height="16">
</button>
<mat-menu #languagemenu="matMenu" class="lang-item-menu">
<div *ngFor="let item of listLang" class="lang-item">
<button mat-menu-item class="dropdown-item lang-item-list"
(click)="setLanguage(item.text, item.lang, item.flag)"
[ngClass]="{'active': langStoreValue === item.lang}">
<img src="{{item.flag}}" class="flag-img" height="12"> <span class="align-middle">{{item.text}}</span>
</button>
</div>
</mat-menu>
</li>
<!-- #START# Notifications-->
<li>
<button mat-button [matMenuTriggerFor]="notificationMenu" class="nav-notification-icons">
<app-feather-icons [icon]="'bell'" [class]="'header-icon'"></app-feather-icons>
</button>
<mat-menu #notificationMenu="matMenu" class="nfc-menu">
<div class="nfc-header">
<h5 class="mb-0">Notitications</h5>
<a class="nfc-mark-as-read">Mark all as read</a>
</div>
<div class="nfc-dropdown">
<ng-scrollbar style="height: 350px" visibility="hover">
<div class="noti-list header-menu">
<div class="menu">
<div>
<button mat-menu-item *ngFor="let notification of notifications" onClick="return false;"
[ngClass]="[notification.status]">
<span class="table-img msg-user ">
<i class="material-icons-two-tone nfc-type-icon"
[ngClass]="[notification.color]">
{{notification.icon}}
</i>
</span>
<span class="menu-info">
<span class="menu-title">{{notification.message}}</span>
<span class="menu-desc mt-2">
<i class="material-icons">access_time</i> {{notification.time}}
</span>
</span>
<span class="nfc-close">
<app-feather-icons [icon]="'x'" [class]="'user-menu-icons'"></app-feather-icons>
</span>
</button>
</div>
</div>
</div>
</ng-scrollbar>
</div>
<div class="nfc-footer">
<a class="nfc-read-all">
Read
All Notifications
</a>
</div>
</mat-menu>
</li>
<!-- #END# Notifications-->
<li class="nav-item user_profile">
<button mat-button [matMenuTriggerFor]="profilemenu">
<div class="chip dropdown-toggle" ngbDropdownToggle class="">
<span>{{userName}}</span>
<img src="{{userImg}}" class="user_img" width="32" height="32" alt="User">
</div>
</button>
<mat-menu #profilemenu="matMenu" class="profile-menu">
<div class="noti-list">
<div class="menu ">
<div class="user_dw_menu">
<button mat-menu-item routerLink="/user/profile">
<app-feather-icons [icon]="'user'" [class]="'user-menu-icons'" routerlink="/user/profile"></app-feather-icons>Account
</button>
<button mat-menu-item>
<app-feather-icons [icon]="'mail'" [class]="'user-menu-icons'"></app-feather-icons>Inbox
</button>
<button mat-menu-item>
<app-feather-icons [icon]="'settings'" [class]="'user-menu-icons'"></app-feather-icons>Settings
</button>
<button mat-menu-item (click)="logout()">
<app-feather-icons [icon]="'log-out'" [class]="'user-menu-icons'"></app-feather-icons>Logout
</button>
</div>
</div>
</div>
</mat-menu>
</li>
<!-- #END# Tasks -->
</ul>
</div>
</div>
</nav>
@@ -0,0 +1 @@
@@ -0,0 +1,23 @@
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();
});
});
@@ -0,0 +1,259 @@
// angular
import { DOCUMENT } from '@angular/common';
import { Component } from '@angular/core';
import { Inject } from '@angular/core';
import { ElementRef } from '@angular/core';
import { OnInit } from '@angular/core';
import { Renderer2 } from '@angular/core';
import { AfterViewInit } from '@angular/core';
import { Router } from '@angular/router';
// libs
// app
import { ConfigService } from 'src/app/config/config.service';
import { InConfiguration } from 'src/app/core/models/config.interface';
import { AuthService } from 'src/app/core/service/auth.service';
import { LanguageService } from 'src/app/core/service/language.service';
import { UnsubscribeOnDestroyAdapter } from 'src/app/shared/UnsubscribeOnDestroyAdapter';
interface Notifications {
message: string;
time: string;
icon: string;
color: string;
status: string;
}
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'],
})
export class HeaderComponent extends UnsubscribeOnDestroyAdapter implements OnInit, AfterViewInit {
config!: InConfiguration;
userImg?: string;
userName?: string;
homePage?: string;
isNavbarCollapsed = true;
flagvalue: string | string[] | undefined;
countryName: string | string[] = [];
langStoreValue?: string;
defaultFlag?: string;
isOpenSidebar?: boolean;
docElement: HTMLElement | undefined;
isFullScreen = false;
constructor(
@Inject(DOCUMENT) private document: Document,
private renderer: Renderer2,
public elementRef: ElementRef,
private configService: ConfigService,
private authService: AuthService,
private router: Router,
public languageService: LanguageService
) {
super();
this.authService.currentUser$.subscribe(user => {
this.setUser();
});
}
listLang = [
{ text: 'English', flag: 'assets/images/flags/us.jpg', lang: 'en' },
{ text: 'Spanish', flag: 'assets/images/flags/spain.jpg', lang: 'es' },
{ text: 'German', flag: 'assets/images/flags/germany.jpg', lang: 'de' },
];
notifications: Notifications[] = [
{
message: 'Please check your mail',
time: '14 mins ago',
icon: 'mail',
color: 'nfc-green',
status: 'msg-unread',
},
{
message: 'New Employee Added..',
time: '22 mins ago',
icon: 'person_add',
color: 'nfc-blue',
status: 'msg-read',
},
{
message: 'Your leave is approved!! ',
time: '3 hours ago',
icon: 'event_available',
color: 'nfc-orange',
status: 'msg-read',
},
{
message: 'Lets break for lunch...',
time: '5 hours ago',
icon: 'lunch_dining',
color: 'nfc-blue',
status: 'msg-read',
},
{
message: 'Employee report generated',
time: '14 mins ago',
icon: 'description',
color: 'nfc-green',
status: 'msg-read',
},
{
message: 'Please check your mail',
time: '22 mins ago',
icon: 'mail',
color: 'nfc-red',
status: 'msg-read',
},
{
message: 'Salary credited...',
time: '3 hours ago',
icon: 'paid',
color: 'nfc-purple',
status: 'msg-read',
},
];
ngOnInit() {
this.config = this.configService.configData;
this.setUser();
this.homePage = 'dashboard/dashboard1';
this.langStoreValue = localStorage.getItem('lang') as string;
const val = this.listLang.filter((x) => x.lang === this.langStoreValue);
this.countryName = val.map((element) => element.text);
if (val.length === 0) {
if (this.flagvalue === undefined) {
this.defaultFlag = 'assets/images/flags/us.jpg';
}
} else {
this.flagvalue = val.map((element) => element.flag);
}
}
ngAfterViewInit() {
// set theme on startup
if (localStorage.getItem('theme')) {
this.renderer.removeClass(this.document.body, this.config.layout.variant);
this.renderer.addClass(
this.document.body,
localStorage.getItem('theme') as string
);
} else {
this.renderer.addClass(this.document.body, this.config.layout.variant);
}
if (localStorage.getItem('menuOption')) {
this.renderer.addClass(
this.document.body,
localStorage.getItem('menuOption') as string
);
} else {
this.renderer.addClass(
this.document.body,
'menu_' + this.config.layout.sidebar.backgroundColor
);
}
if (localStorage.getItem('choose_logoheader')) {
this.renderer.addClass(
this.document.body,
localStorage.getItem('choose_logoheader') as string
);
} else {
this.renderer.addClass(
this.document.body,
'logo-' + this.config.layout.logo_bg_color
);
}
if (localStorage.getItem('sidebar_status')) {
if (localStorage.getItem('sidebar_status') === 'close') {
this.renderer.addClass(this.document.body, 'side-closed');
this.renderer.addClass(this.document.body, 'submenu-closed');
} else {
this.renderer.removeClass(this.document.body, 'side-closed');
this.renderer.removeClass(this.document.body, 'submenu-closed');
}
} else {
if (this.config.layout.sidebar.collapsed === true) {
this.renderer.addClass(this.document.body, 'side-closed');
this.renderer.addClass(this.document.body, 'submenu-closed');
}
}
}
callFullscreen() {
if (!this.isFullScreen) {
this.docElement?.requestFullscreen();
} else {
document.exitFullscreen();
}
this.isFullScreen = !this.isFullScreen;
}
setLanguage(text: string, lang: string, flag: string) {
this.countryName = text;
this.flagvalue = flag;
this.langStoreValue = lang;
this.languageService.setLanguage(lang);
}
mobileMenuSidebarOpen(event: Event, className: string) {
const hasClass = (event.target as HTMLInputElement).classList.contains(
className
);
if (hasClass) {
this.renderer.removeClass(this.document.body, className);
} else {
this.renderer.addClass(this.document.body, className);
}
const hasClass2 = this.document.body.classList.contains('side-closed');
if (hasClass2) {
// this.renderer.removeClass(this.document.body, "side-closed");
this.renderer.removeClass(this.document.body, 'submenu-closed');
} else {
// this.renderer.addClass(this.document.body, "side-closed");
this.renderer.addClass(this.document.body, 'submenu-closed');
}
}
callSidemenuCollapse() {
const hasClass = this.document.body.classList.contains('side-closed');
if (hasClass) {
this.renderer.removeClass(this.document.body, 'side-closed');
this.renderer.removeClass(this.document.body, 'submenu-closed');
} else {
this.renderer.addClass(this.document.body, 'side-closed');
this.renderer.addClass(this.document.body, 'submenu-closed');
}
}
logout() {
this.subs.sink = this.authService.logout().subscribe((res) => {
if (!res.success) {
this.router.navigate(['/authentication/signin']);
}
});
}
private setUser() {
this.userImg = this.authService.currentUserValue.img;
this.userName = [
this.authService.currentUserValue.firstName,
this.authService.currentUserValue.lastName
].join(' ').trim();
this.userName = this.userName || this.authService.currentUserValue.username;
}
}
@@ -0,0 +1,23 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatTabsModule } from '@angular/material/tabs';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { MatButtonModule } from '@angular/material/button';
import { MatInputModule } from '@angular/material/input';
import { MatBadgeModule } from '@angular/material/badge';
@NgModule({
imports: [
CommonModule,
MatTabsModule,
MatMenuModule,
MatIconModule,
MatButtonModule,
MatInputModule,
MatBadgeModule,
],
declarations: [],
})
export class LayoutModule {
}
@@ -0,0 +1,2 @@
<ngx-loading-bar color="#3173D6" ref="router"></ngx-loading-bar>
<ngx-loading-bar color="#31d662" ref="http"></ngx-loading-bar>
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { PageLoaderComponent } from './page-loader.component';
describe('PageLoaderComponent',
() => {
let component: PageLoaderComponent;
let fixture: ComponentFixture<PageLoaderComponent>;
beforeEach(
waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [PageLoaderComponent],
}).compileComponents();
})
);
beforeEach(() => {
fixture = TestBed.createComponent(PageLoaderComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create',
() => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,12 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-page-loader',
templateUrl: './page-loader.component.html',
styleUrls: ['./page-loader.component.scss'],
})
export class PageLoaderComponent {
constructor() {
// constructor
}
}
@@ -0,0 +1,76 @@
<div class="settingSidebar" [ngClass]="isOpenSidebar ? 'showSettingPanel' : ''">
<a href="javascript:void(0)" class="settingPanelToggle" (click)="toggleRightSidebar()">
<app-feather-icons [icon]="'settings'" [class]="'setting-sidebar-icon'"></app-feather-icons>
</a>
<ng-scrollbar [style.height]="maxHeight + 'px'" visibility="hover">
<div class="settingSidebar-body ps-container ps-theme-default">
<div class=" fade show active">
<div class="setting-panel-header">
Setting Panel
</div>
<div class="p-15 border-bottom">
<h6 class="font-medium m-b-10">Select Layout</h6>
<div class="flex flex-wrap hiddenradio">
<div class="flex flex-col ">
<label>
<input type="radio" name="value" value="light" [checked]="isDarTheme === false ? true : false"
(click)="lightThemeBtnClick()">
<img src="assets/images/light.png">
</label>
<div class="mt-1 text-md text-center"> Light </div>
</div>
<div class="flex flex-col mt-3">
<label>
<input type="radio" name="value" value="dark" [checked]="isDarTheme === true ? true : false"
(click)="darkThemeBtnClick()">
<img src="assets/images/dark.png">
</label>
<div class="mt-1 text-md text-center"> Dark </div>
</div>
</div>
</div>
<div class="rightSetting">
<h6 class="font-medium m-b-10">Sidebar Menu Color</h6>
<mat-button-toggle-group class="mt-2" [value]="isDarkSidebar ? 'dark' : 'light'">
<mat-button-toggle (click)="lightSidebarBtnClick()" value="light">Light</mat-button-toggle>
<mat-button-toggle (click)="darkSidebarBtnClick()" value="dark">Dark</mat-button-toggle>
</mat-button-toggle-group>
</div>
<div class="p-15 border-bottom">
<h6 class="font-medium m-b-10">Color Theme</h6>
<div class="theme-setting-options">
<ul class="choose-theme list-unstyled mb-0">
<li data-theme="white" [ngClass]="{'active': selectedBgColor === 'white'}" (click)="selectTheme('white')">
<div class="white"></div>
</li>
<li data-theme="black" [ngClass]="{'active': selectedBgColor === 'black'}" (click)="selectTheme('black')">
<div class="black"></div>
</li>
<li data-theme="purple" [ngClass]="{'active': selectedBgColor === 'purple'}"
(click)="selectTheme('purple')">
<div class="purple"></div>
</li>
<li data-theme="orange" [ngClass]="{'active': selectedBgColor === 'orange'}"
(click)="selectTheme('orange')">
<div class="orange"></div>
</li>
<li data-theme="cyan" [ngClass]="{'active': selectedBgColor === 'cyan'}" (click)="selectTheme('cyan')">
<div class="cyan"></div>
</li>
<li data-theme="green" [ngClass]="{'active': selectedBgColor === 'green'}" (click)="selectTheme('green')">
<div class="green"></div>
</li>
<li data-theme="blue" [ngClass]="{'active': selectedBgColor === 'blue'}" (click)="selectTheme('blue')">
<div class="blue"></div>
</li>
</ul>
</div>
</div>
<div class="rightSetting">
<h6 class="font-medium m-b-10">RTL Layout</h6>
<mat-slide-toggle class="mt-2" [checked]="isRtl" (change)="switchDirection($event)"></mat-slide-toggle>
</div>
</div>
</div>
</ng-scrollbar>
</div>
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { RightSidebarComponent } from './right-sidebar.component';
describe('RightSidebarComponent',
() => {
let component: RightSidebarComponent;
let fixture: ComponentFixture<RightSidebarComponent>;
beforeEach(
waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [RightSidebarComponent],
}).compileComponents();
})
);
beforeEach(() => {
fixture = TestBed.createComponent(RightSidebarComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create',
() => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,269 @@
import { DOCUMENT } from '@angular/common';
import {
Component,
Inject,
ElementRef,
OnInit,
AfterViewInit,
Renderer2,
ChangeDetectionStrategy,
} from '@angular/core';
import { ConfigService } from 'src/app/config/config.service';
import { RightSidebarService } from 'src/app/core/service/rightsidebar.service';
import { MatSlideToggleChange } from '@angular/material/slide-toggle';
import { UnsubscribeOnDestroyAdapter } from 'src/app/shared/UnsubscribeOnDestroyAdapter';
import { DirectionService } from 'src/app/core/service/direction.service';
import { InConfiguration } from 'src/app/core/models/config.interface';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'app-right-sidebar',
templateUrl: './right-sidebar.component.html',
styleUrls: ['./right-sidebar.component.scss'],
})
export class RightSidebarComponent
extends UnsubscribeOnDestroyAdapter
implements OnInit, AfterViewInit {
selectedBgColor = 'white';
maxHeight!: string;
maxWidth!: string;
showpanel = false;
isOpenSidebar!: boolean;
isDarkSidebar = false;
isDarTheme = false;
innerHeight?: number;
headerHeight = 60;
isRtl = false;
config!: InConfiguration;
constructor(
@Inject(DOCUMENT) private document: Document,
private renderer: Renderer2,
public elementRef: ElementRef,
private rightSidebarService: RightSidebarService,
private configService: ConfigService,
private directionService: DirectionService
) {
super();
}
ngOnInit() {
this.config = this.configService.configData;
this.subs.sink = this.rightSidebarService.sidebarState.subscribe(
(isRunning) => {
this.isOpenSidebar = isRunning;
}
);
this.setRightSidebarWindowHeight();
}
ngAfterViewInit() {
// set header color on startup
if (localStorage.getItem('choose_skin')) {
this.renderer.addClass(
this.document.body,
localStorage.getItem('choose_skin') as string
);
this.selectedBgColor = localStorage.getItem(
'choose_skin_active'
) as string;
} else {
this.renderer.addClass(
this.document.body,
'theme-' + this.config.layout.theme_color
);
this.selectedBgColor = this.config.layout.theme_color;
}
if (localStorage.getItem('menuOption')) {
if (localStorage.getItem('menuOption') === 'menu_dark') {
this.isDarkSidebar = true;
} else if (localStorage.getItem('menuOption') === 'menu_light') {
this.isDarkSidebar = false;
} else {
this.isDarkSidebar =
this.config.layout.sidebar.backgroundColor === 'dark' ? true : false;
}
} else {
this.isDarkSidebar =
this.config.layout.sidebar.backgroundColor === 'dark' ? true : false;
}
if (localStorage.getItem('theme')) {
if (localStorage.getItem('theme') === 'dark') {
this.isDarTheme = true;
} else if (localStorage.getItem('theme') === 'light') {
this.isDarTheme = false;
} else {
this.isDarTheme = this.config.layout.variant === 'dark' ? true : false;
}
} else {
this.isDarTheme = this.config.layout.variant === 'dark' ? true : false;
}
if (localStorage.getItem('isRtl')) {
if (localStorage.getItem('isRtl') === 'true') {
this.setRTLSettings();
} else if (localStorage.getItem('isRtl') === 'false') {
this.setLTRSettings();
}
} else {
if (this.config.layout.rtl == true) {
this.setRTLSettings();
} else {
this.setLTRSettings();
}
}
}
selectTheme(e: string) {
this.selectedBgColor = e;
const prevTheme = this.elementRef.nativeElement
.querySelector('.settingSidebar .choose-theme li.active')
.getAttribute('data-theme');
this.renderer.removeClass(this.document.body, 'theme-' + prevTheme);
this.renderer.addClass(this.document.body, 'theme-' + this.selectedBgColor);
localStorage.setItem('choose_skin', 'theme-' + this.selectedBgColor);
localStorage.setItem('choose_skin_active', this.selectedBgColor);
}
lightSidebarBtnClick() {
this.renderer.removeClass(this.document.body, 'menu_dark');
this.renderer.removeClass(this.document.body, 'logo-black');
this.renderer.addClass(this.document.body, 'menu_light');
this.renderer.addClass(this.document.body, 'logo-white');
const menuOption = 'menu_light';
localStorage.setItem('choose_logoheader', 'logo-white');
localStorage.setItem('menuOption', menuOption);
}
darkSidebarBtnClick() {
this.renderer.removeClass(this.document.body, 'menu_light');
this.renderer.removeClass(this.document.body, 'logo-white');
this.renderer.addClass(this.document.body, 'menu_dark');
this.renderer.addClass(this.document.body, 'logo-black');
const menuOption = 'menu_dark';
localStorage.setItem('choose_logoheader', 'logo-black');
localStorage.setItem('menuOption', menuOption);
}
lightThemeBtnClick() {
this.renderer.removeClass(this.document.body, 'dark');
this.renderer.removeClass(this.document.body, 'submenu-closed');
this.renderer.removeClass(this.document.body, 'menu_dark');
this.renderer.removeClass(this.document.body, 'logo-black');
if (localStorage.getItem('choose_skin')) {
this.renderer.removeClass(
this.document.body,
localStorage.getItem('choose_skin') as string
);
} else {
this.renderer.removeClass(
this.document.body,
'theme-' + this.config.layout.theme_color
);
}
this.renderer.addClass(this.document.body, 'light');
this.renderer.addClass(this.document.body, 'submenu-closed');
this.renderer.addClass(this.document.body, 'menu_light');
this.renderer.addClass(this.document.body, 'logo-white');
this.renderer.addClass(this.document.body, 'theme-white');
const theme = 'light';
const menuOption = 'menu_light';
this.selectedBgColor = 'white';
this.isDarkSidebar = false;
localStorage.setItem('choose_logoheader', 'logo-white');
localStorage.setItem('choose_skin', 'theme-white');
localStorage.setItem('theme', theme);
localStorage.setItem('menuOption', menuOption);
}
darkThemeBtnClick() {
this.renderer.removeClass(this.document.body, 'light');
this.renderer.removeClass(this.document.body, 'submenu-closed');
this.renderer.removeClass(this.document.body, 'menu_light');
this.renderer.removeClass(this.document.body, 'logo-white');
if (localStorage.getItem('choose_skin')) {
this.renderer.removeClass(
this.document.body,
localStorage.getItem('choose_skin') as string
);
} else {
this.renderer.removeClass(
this.document.body,
'theme-' + this.config.layout.theme_color
);
}
this.renderer.addClass(this.document.body, 'dark');
this.renderer.addClass(this.document.body, 'submenu-closed');
this.renderer.addClass(this.document.body, 'menu_dark');
this.renderer.addClass(this.document.body, 'logo-black');
this.renderer.addClass(this.document.body, 'theme-black');
const theme = 'dark';
const menuOption = 'menu_dark';
this.selectedBgColor = 'black';
this.isDarkSidebar = true;
localStorage.setItem('choose_logoheader', 'logo-black');
localStorage.setItem('choose_skin', 'theme-black');
localStorage.setItem('theme', theme);
localStorage.setItem('menuOption', menuOption);
}
setRightSidebarWindowHeight() {
this.innerHeight = window.innerHeight;
const height = this.innerHeight - this.headerHeight;
this.maxHeight = height + '';
this.maxWidth = '500px';
}
onClickedOutside(event: Event) {
const button = event.target as HTMLButtonElement;
if (button.id !== 'settingBtn') {
if (this.isOpenSidebar === true) {
this.toggleRightSidebar();
}
}
}
toggleRightSidebar(): void {
this.rightSidebarService.setRightSidebar(
(this.isOpenSidebar = !this.isOpenSidebar)
);
}
switchDirection(event: MatSlideToggleChange) {
const isrtl = String(event.checked);
if (
isrtl === 'false' &&
document.getElementsByTagName('html')[0].hasAttribute('dir')
) {
document.getElementsByTagName('html')[0].removeAttribute('dir');
this.renderer.removeClass(this.document.body, 'rtl');
this.directionService.updateDirection('ltr');
} else if (
isrtl === 'true' &&
!document.getElementsByTagName('html')[0].hasAttribute('dir')
) {
document.getElementsByTagName('html')[0].setAttribute('dir', 'rtl');
this.renderer.addClass(this.document.body, 'rtl');
this.directionService.updateDirection('rtl');
}
localStorage.setItem('isRtl', isrtl);
this.isRtl = event.checked;
}
setRTLSettings() {
document.getElementsByTagName('html')[0].setAttribute('dir', 'rtl');
this.renderer.addClass(this.document.body, 'rtl');
this.isRtl = true;
localStorage.setItem('isRtl', 'true');
}
setLTRSettings() {
document.getElementsByTagName('html')[0].removeAttribute('dir');
this.renderer.removeClass(this.document.body, 'rtl');
this.isRtl = false;
localStorage.setItem('isRtl', 'false');
}
}
@@ -0,0 +1,209 @@
import { RouteInfo } from './sidebar.metadata';
export const ROUTES: RouteInfo[] = [
{
path: '',
title: 'MENUITEMS.MAIN.TEXT',
iconType: '',
icon: '',
class: '',
groupTitle: true,
badge: '',
badgeClass: '',
submenu: [],
},
{
path: '',
title: 'MENUITEMS.DASHBOARD.TEXT',
iconType: 'feather',
icon: 'home',
class: 'menu-toggle',
groupTitle: false,
badge: '',
badgeClass: '',
submenu: [
{
path: 'dashboard/dashboard1',
title: 'MENUITEMS.DASHBOARD.LIST.DASHBOARD1',
iconType: '',
icon: '',
class: 'ml-menu',
groupTitle: false,
badge: '',
badgeClass: '',
submenu: [],
},
{
path: 'dashboard/dashboard2',
title: 'MENUITEMS.DASHBOARD.LIST.DASHBOARD2',
iconType: '',
icon: '',
class: 'ml-menu',
groupTitle: false,
badge: '',
badgeClass: '',
submenu: [],
},
],
},
// Common Modules
{
path: '',
title: 'Authentication',
iconType: 'feather',
icon: 'user-check',
class: 'menu-toggle',
groupTitle: false,
badge: '',
badgeClass: '',
submenu: [
{
path: '/authentication/forgot-password',
title: 'Forgot Password',
iconType: '',
icon: '',
class: 'ml-menu',
groupTitle: false,
badge: '',
badgeClass: '',
submenu: [],
},
{
path: '/authentication/locked',
title: 'Locked',
iconType: '',
icon: '',
class: 'ml-menu',
groupTitle: false,
badge: '',
badgeClass: '',
submenu: [],
},
{
path: '/authentication/page404',
title: '404 - Not Found',
iconType: '',
icon: '',
class: 'ml-menu',
groupTitle: false,
badge: '',
badgeClass: '',
submenu: [],
},
{
path: '/authentication/page500',
title: '500 - Server Error',
iconType: '',
icon: '',
class: 'ml-menu',
groupTitle: false,
badge: '',
badgeClass: '',
submenu: [],
},
],
},
{
path: '',
title: 'Extra Pages',
iconType: 'feather',
icon: 'anchor',
class: 'menu-toggle',
groupTitle: false,
badge: '',
badgeClass: '',
submenu: [
{
path: '/extra-pages/blank',
title: 'Blank Page',
iconType: '',
icon: '',
class: 'ml-menu',
groupTitle: false,
badge: '',
badgeClass: '',
submenu: [],
},
],
},
{
path: '',
title: 'Multi level Menu',
iconType: 'feather',
icon: 'chevrons-down',
class: 'menu-toggle',
groupTitle: false,
badge: '',
badgeClass: '',
submenu: [
{
path: '/multilevel/first1',
title: 'First',
iconType: '',
icon: '',
class: 'ml-menu',
groupTitle: false,
badge: '',
badgeClass: '',
submenu: [],
},
{
path: '/',
title: 'Second',
iconType: '',
icon: '',
class: 'ml-sub-menu',
groupTitle: false,
badge: '',
badgeClass: '',
submenu: [
{
path: '/multilevel/secondlevel/second1',
title: 'Second 1',
iconType: '',
icon: '',
class: 'ml-menu2',
groupTitle: false,
badge: '',
badgeClass: '',
submenu: [],
},
{
path: '/',
title: 'Second 2',
iconType: '',
icon: '',
class: 'ml-sub-menu2',
groupTitle: false,
badge: '',
badgeClass: '',
submenu: [
{
path: '/multilevel/thirdlevel/third1',
title: 'third 1',
iconType: '',
icon: '',
class: 'ml-menu3',
groupTitle: false,
badge: '',
badgeClass: '',
submenu: [],
},
],
},
],
},
{
path: '/multilevel/first3',
title: 'Third',
iconType: '',
icon: '',
class: 'ml-menu',
groupTitle: false,
badge: '',
badgeClass: '',
submenu: [],
},
],
},
];
@@ -0,0 +1,75 @@
<div>
<!-- Left Sidebar -->
<aside id="leftsidebar" class="sidebar" (mouseenter)="mouseHover()" (mouseleave)="mouseOut()">
<div class="navbar-header">
<ul class="nav navbar-nav flex-row">
<li class="nav-item logo">
<a class="navbar-brand" routerLink="dashboard/dashboard1">
<img src="assets/images/logo.png" alt=""/>
<span class="logo-name">ase.com.ua</span>
</a>
</li>
<li class="nav-item nav-toggle">
<button mat-icon-button (click)="callSidemenuCollapse()" class="sidemenu-collapse">
<mat-icon [ngStyle]="{'color':'#8F8C91'}" class="menuIcon">{{menuIcon}}</mat-icon>
</button>
</li>
</ul>
</div>
<!-- Menu -->
<div class="menu">
<ng-scrollbar [style.height]="listMaxHeight + 'px'" visibility="hover">
<ul class="list">
<!-- Top Most level menu -->
<li *ngFor="let sidebarItem of sidebarItems"
[routerLinkActive]="sidebarItem.submenu.length !== 0 ? 'active' : 'active-top'">
<div class="header" *ngIf="sidebarItem.groupTitle === true">{{sidebarItem.title | translate}}</div>
<a [routerLink]="sidebarItem.class === '' ? [sidebarItem.path] : null" *ngIf="!sidebarItem.groupTitle;"
[ngClass]="[sidebarItem.class]" (click)="callToggleMenu($event, sidebarItem.submenu.length)"
class="menu-top">
<i-feather [name]="sidebarItem.icon" class="sidebarIcon"></i-feather>
<span class="hide-menu">
{{sidebarItem.title | translate}}
</span>
<span *ngIf="sidebarItem.badge !== '' " [ngClass]="[sidebarItem.badgeClass]">{{sidebarItem.badge}}</span>
</a>
<!-- First level menu -->
<ul class="ml-menu" *ngIf="sidebarItem.submenu.length > 0">
<li *ngFor="let sidebarSubItem1 of sidebarItem.submenu"
[routerLinkActive]="sidebarSubItem1.submenu.length > 0 ? '' : 'active'">
<a [routerLink]="sidebarSubItem1.submenu.length > 0 ? null : [sidebarSubItem1.path]"
(click)="callToggleMenu($event,sidebarSubItem1.submenu.length)" [ngClass]="[sidebarSubItem1.class]">
{{sidebarSubItem1.title | translate}}
</a>
<!-- Second level menu -->
<ul class="ml-menu-2" *ngIf="sidebarSubItem1.submenu.length > 0">
<li *ngFor="let sidebarSubItem2 of sidebarSubItem1.submenu"
[routerLinkActive]="sidebarSubItem2.submenu.length > 0 ? '' : 'active'">
<a [routerLink]="sidebarSubItem2.submenu.length > 0 ? null : [sidebarSubItem2.path]"
(click)="callToggleMenu($event,sidebarSubItem2.submenu.length)"
[ngClass]="[sidebarSubItem2.class]">
{{sidebarSubItem2.title | translate}}
</a>
<!-- Third level menu -->
<ul class="ml-menu-3" *ngIf="sidebarSubItem2.submenu.length > 0">
<li *ngFor="let sidebarSubItem3 of sidebarSubItem2.submenu"
[routerLinkActive]="sidebarSubItem3.submenu.length > 0 ? '' : 'active'">
<a [routerLink]="sidebarSubItem3.submenu.length > 0 ? null : [sidebarSubItem3.path]"
(click)="callToggleMenu($event,sidebarSubItem3.submenu.length)"
[ngClass]="[sidebarSubItem3.class]">
{{sidebarSubItem3.title | translate}}
</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</ng-scrollbar>
</div>
<!-- #Menu -->
</aside>
<!-- #END# Left Sidebar -->
</div>
@@ -0,0 +1 @@
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { SidebarComponent } from './sidebar.component';
describe('SidebarComponent',
() => {
let component: SidebarComponent;
let fixture: ComponentFixture<SidebarComponent>;
beforeEach(
waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [SidebarComponent],
}).compileComponents();
})
);
beforeEach(() => {
fixture = TestBed.createComponent(SidebarComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create',
() => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,174 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
// angular
import { Router, NavigationEnd } from '@angular/router';
import { DOCUMENT } from '@angular/common';
import { Component, Inject, ElementRef, OnInit, Renderer2, HostListener, OnDestroy } from '@angular/core';
// app
import { ROUTES } from './sidebar-items';
import { AuthService } from 'src/app/core/service/auth.service';
import { RouteInfo } from './sidebar.metadata';
@Component({
selector: 'app-sidebar',
templateUrl: './sidebar.component.html',
styleUrls: ['./sidebar.component.scss'],
})
export class SidebarComponent implements OnInit, OnDestroy {
sidebarItems!: RouteInfo[];
innerHeight?: number;
bodyTag!: HTMLElement;
listMaxHeight?: string;
listMaxWidth?: string;
userFullName?: string;
userImg?: string;
userType?: string;
headerHeight = 60;
currentRoute?: string;
routerObj;
menuIcon = 'radio_button_checked';
constructor(
@Inject(DOCUMENT) private document: Document,
private renderer: Renderer2,
public elementRef: ElementRef,
private authService: AuthService,
private router: Router
) {
this.elementRef.nativeElement.closest('body');
this.routerObj = this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
// close sidebar on mobile screen after menu select
this.renderer.removeClass(this.document.body, 'overlay-open');
}
});
}
@HostListener('window:resize', ['$event'])
windowResizecall() {
this.setMenuHeight();
this.checkStatuForResize(false);
}
@HostListener('document:mousedown', ['$event'])
onGlobalClick(event: Event): void {
if (!this.elementRef.nativeElement.contains(event.target)) {
this.renderer.removeClass(this.document.body, 'overlay-open');
}
}
callToggleMenu(event: Event, length: number) {
if (length > 0) {
const parentElement = (event.target as HTMLInputElement).closest('li');
const activeClass = parentElement?.classList.contains('active');
if (activeClass) {
this.renderer.removeClass(parentElement, 'active');
} else {
this.renderer.addClass(parentElement, 'active');
}
}
}
ngOnInit() {
if (this.authService.currentUserValue) {
this.userFullName =
this.authService.currentUserValue.firstName +
' ' +
this.authService.currentUserValue.lastName;
this.userImg = this.authService.currentUserValue.img;
this.userType = 'Admin';
this.sidebarItems = ROUTES.filter((sidebarItem) => sidebarItem);
}
// this.sidebarItems = ROUTES.filter((sidebarItem) => sidebarItem);
this.initLeftSidebar();
this.bodyTag = this.document.body;
}
ngOnDestroy() {
this.routerObj.unsubscribe();
}
initLeftSidebar() {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const _this = this;
// Set menu height
_this.setMenuHeight();
_this.checkStatuForResize(true);
}
setMenuHeight() {
this.innerHeight = window.innerHeight;
const height = this.innerHeight - this.headerHeight;
this.listMaxHeight = height + '';
this.listMaxWidth = '500px';
}
isOpen() {
return this.bodyTag.classList.contains('overlay-open');
}
checkStatuForResize(firstTime: boolean) {
if (window.innerWidth < 1170) {
this.renderer.addClass(this.document.body, 'ls-closed');
} else {
this.renderer.removeClass(this.document.body, 'ls-closed');
}
}
mouseHover() {
const body = this.elementRef.nativeElement.closest('body');
if (body.classList.contains('submenu-closed')) {
this.renderer.addClass(this.document.body, 'side-closed-hover');
this.renderer.removeClass(this.document.body, 'submenu-closed');
}
}
mouseOut() {
const body = this.elementRef.nativeElement.closest('body');
if (body.classList.contains('side-closed-hover')) {
this.renderer.removeClass(this.document.body, 'side-closed-hover');
this.renderer.addClass(this.document.body, 'submenu-closed');
}
}
mobileMenuSidebarOpen(event: Event, className: string) {
const hasClass = (event.target as HTMLInputElement).classList.contains(
className
);
if (hasClass) {
this.renderer.removeClass(this.document.body, className);
} else {
this.renderer.addClass(this.document.body, className);
}
}
callSidemenuCollapse() {
const hasClass = this.document.body.classList.contains('side-closed');
if (hasClass) {
this.renderer.removeClass(this.document.body, 'side-closed');
this.renderer.removeClass(this.document.body, 'submenu-closed');
this.menuIcon = 'radio_button_checked';
} else {
this.renderer.addClass(this.document.body, 'side-closed');
this.renderer.addClass(this.document.body, 'submenu-closed');
this.menuIcon = 'radio_button_unchecked';
}
const sideClosedHover =
this.document.body.classList.contains('side-closed');
if (sideClosedHover) {
this.renderer.removeClass(this.document.body, 'side-closed-hover');
}
}
logout() {
this.authService.logout().subscribe((res) => {
if (!res.success) {
console.log('sidebar.logout');
this.router.navigate(['/authentication/signin']);
}
});
}
}
@@ -0,0 +1,12 @@
// Sidebar route metadata
export interface RouteInfo {
path: string;
title: string;
iconType: string;
icon: string;
class: string;
groupTitle: boolean;
badge: string;
badgeClass: string;
submenu: RouteInfo[];
}