ez-nav
Version:
A responsive, configurable Angular navigation bar component with support for dropdown menus, mobile drawer toggles, and custom layouts. Easily integrate a dynamic navbar using a simple configuration object.
140 lines (133 loc) • 14.1 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, EventEmitter, Output, Input, Component, NgModule } from '@angular/core';
import * as i2 from '@angular/common';
import { CommonModule } from '@angular/common';
import { RouterLink, RouterModule } from '@angular/router';
import { BehaviorSubject } from 'rxjs';
class ScreenSizeService {
ngZone;
screenWidthSubject = new BehaviorSubject("desktop");
screenWidth$ = this.screenWidthSubject.asObservable();
constructor(ngZone) {
this.ngZone = ngZone;
// Listen to window resize in the service
if (window.innerWidth <= 600) {
this.screenWidthSubject.next("mobile");
}
else if (window.innerWidth > 600 && window.innerWidth <= 1024) {
this.screenWidthSubject.next("tablet");
}
else if (window.innerWidth > 1024) {
this.screenWidthSubject.next("desktop");
}
this.listenToResize();
}
listenToResize() {
this.ngZone.runOutsideAngular(() => {
window.addEventListener('resize', () => {
this.ngZone.run(() => {
if (window.innerWidth <= 600) {
this.screenWidthSubject.next("mobile");
}
else if (window.innerWidth > 600 && window.innerWidth <= 1024) {
this.screenWidthSubject.next("tablet");
}
else if (window.innerWidth > 1024) {
this.screenWidthSubject.next("desktop");
}
});
});
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: ScreenSizeService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: ScreenSizeService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: ScreenSizeService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [{ type: i0.NgZone }] });
class NavDrawerComponent {
screenSizeService;
navRow;
drawerPosition = new EventEmitter(false);
screenType = null;
isDrawerOpen = false;
screenSizeSubscription;
subNavsOpen = [];
constructor(screenSizeService) {
this.screenSizeService = screenSizeService;
}
ngOnInit() {
this.screenSizeSubscription = this.screenSizeService.screenWidth$.subscribe(screenType => {
this.screenType = screenType;
});
this.subNavsOpen = this.navRow.items.map(item => !!item.subNav?.length && false);
}
toggleSubNav(index, event) {
event.preventDefault();
event.stopPropagation();
// Close all others, open the clicked one
this.subNavsOpen = this.subNavsOpen.map((open, i) => i === index ? !open : false);
}
ngOnDestroy() {
if (this.screenSizeSubscription) {
this.screenSizeSubscription.unsubscribe();
}
}
updateDrawer(drawerPosition) {
this.isDrawerOpen = drawerPosition;
this.drawerPosition.emit(drawerPosition);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: NavDrawerComponent, deps: [{ token: ScreenSizeService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.9", type: NavDrawerComponent, isStandalone: true, selector: "ez-nav-nav-drawer", inputs: { navRow: "navRow" }, outputs: { drawerPosition: "drawerPosition" }, ngImport: i0, template: "\n<div class=\"row\">\n <ng-container *ngIf=\"screenType === 'desktop' || screenType === 'tablet'\">\n <ng-container *ngFor=\"let link of navRow.items; let i = index\">\n <div [ngClass]=\"link.gridClasses\" (click)=\"toggleSubNav(i, $event)\">\n <a [routerLink]=\"link.route\" [ngClass]=\"link.anchorTagClass\" class=\"d-flex align-items-center gap-1\">\n <span>{{ link.title }}</span>\n\n <!-- Subnav Icons -->\n <ng-container *ngIf=\"link.subNav?.length\">\n <i class=\"bi\"\n [ngClass]=\"subNavsOpen[i] ? link.subNavOpenClasses : link.subNavCloseClasses\"\n style=\"cursor: pointer;\">\n </i>\n </ng-container>\n </a>\n\n <div *ngIf=\"subNavsOpen[i]\" [ngClass]=\"link.dropDownParentClasses\">\n <ng-container *ngFor=\"let sub of link.subNav\">\n <div>\n <a\n [routerLink]=\"sub.route\"\n [ngClass]=\"sub.cssClasses\">\n {{ sub.title }}\n </a>\n </div>\n </ng-container>\n </div>\n\n </div>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"screenType==='mobile'\">\n <!--\n drawerIcon bi bi-filter-right\n drawerIcon bi bi-filter-left\n -->\n <i (click)=\"updateDrawer(true)\" *ngIf=\"!isDrawerOpen\" [ngClass]=\"navRow.drawerIconOpen\"></i>\n <i (click)=\"updateDrawer(false)\" *ngIf=\"isDrawerOpen\" [ngClass]=\"navRow.drawerIconClosed\"></i>\n </ng-container>\n </div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: NavDrawerComponent, decorators: [{
type: Component,
args: [{ selector: 'ez-nav-nav-drawer', standalone: true, imports: [CommonModule, RouterLink], template: "\n<div class=\"row\">\n <ng-container *ngIf=\"screenType === 'desktop' || screenType === 'tablet'\">\n <ng-container *ngFor=\"let link of navRow.items; let i = index\">\n <div [ngClass]=\"link.gridClasses\" (click)=\"toggleSubNav(i, $event)\">\n <a [routerLink]=\"link.route\" [ngClass]=\"link.anchorTagClass\" class=\"d-flex align-items-center gap-1\">\n <span>{{ link.title }}</span>\n\n <!-- Subnav Icons -->\n <ng-container *ngIf=\"link.subNav?.length\">\n <i class=\"bi\"\n [ngClass]=\"subNavsOpen[i] ? link.subNavOpenClasses : link.subNavCloseClasses\"\n style=\"cursor: pointer;\">\n </i>\n </ng-container>\n </a>\n\n <div *ngIf=\"subNavsOpen[i]\" [ngClass]=\"link.dropDownParentClasses\">\n <ng-container *ngFor=\"let sub of link.subNav\">\n <div>\n <a\n [routerLink]=\"sub.route\"\n [ngClass]=\"sub.cssClasses\">\n {{ sub.title }}\n </a>\n </div>\n </ng-container>\n </div>\n\n </div>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"screenType==='mobile'\">\n <!--\n drawerIcon bi bi-filter-right\n drawerIcon bi bi-filter-left\n -->\n <i (click)=\"updateDrawer(true)\" *ngIf=\"!isDrawerOpen\" [ngClass]=\"navRow.drawerIconOpen\"></i>\n <i (click)=\"updateDrawer(false)\" *ngIf=\"isDrawerOpen\" [ngClass]=\"navRow.drawerIconClosed\"></i>\n </ng-container>\n </div>\n" }]
}], ctorParameters: () => [{ type: ScreenSizeService }], propDecorators: { navRow: [{
type: Input
}], drawerPosition: [{
type: Output
}] } });
class EzNavComponent {
header;
isDrawerOpen = false;
subNavsOpen = [];
ngOnInit() {
this.subNavsOpen = this.header.navRow.items.map(item => !!(item.subNav && item.subNav.length > 0) ? false : false);
}
toggleSubNav(index) {
this.subNavsOpen[index] = !this.subNavsOpen[index];
}
handleDrawerStatus(status) {
this.isDrawerOpen = status;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: EzNavComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.9", type: EzNavComponent, isStandalone: true, selector: "ez-nav", inputs: { header: "header" }, ngImport: i0, template: "<div [ngClass]=\"header.wrappingClass\">\n <div class=\"row\">\n <div [ngClass]=\"header.parentRowLogoClasses\">\n <img [src]=\"header.logo.src\" [alt]=\"header.logo.alt\" [ngClass]=\"header.logo.imageClassNames\" />\n </div>\n <div [ngClass]=\"header.parentNavItemsClasses\">\n <ez-nav-nav-drawer (drawerPosition)=\"handleDrawerStatus($event)\" [navRow]=\"header.navRow\"></ez-nav-nav-drawer>\n </div>\n </div>\n <div *ngIf=\"isDrawerOpen\">\n <ng-container *ngFor=\"let link of header.navRow.items; let i = index\">\n <div class=\"col-md-12 col-sm-12\" (click)=\"toggleSubNav(i); $event.preventDefault(); $event.stopPropagation();\">\n <a [ngClass]=\"link.anchorTagClassMobile\" [routerLink]=\"link.route\">\n {{ link.title }}\n <ng-container *ngIf=\"link.subNav?.length\">\n <i\n class=\"bi\"\n [ngClass]=\"subNavsOpen[i] ? link.subNavOpenClasses : link.subNavCloseClasses\">\n </i>\n </ng-container>\n </a>\n </div>\n <ng-container *ngIf=\"subNavsOpen[i] && link.subNav?.length\">\n <div class=\"row\">\n <a *ngFor=\"let sub of link.subNav\" [routerLink]=\"sub.route\" [ngClass]=\"sub.cssClasses\">\n {{ sub.title }}\n </a>\n </div>\n </ng-container>\n </ng-container>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: NavDrawerComponent, selector: "ez-nav-nav-drawer", inputs: ["navRow"], outputs: ["drawerPosition"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: EzNavComponent, decorators: [{
type: Component,
args: [{ selector: 'ez-nav', standalone: true, imports: [CommonModule, RouterLink, NavDrawerComponent], template: "<div [ngClass]=\"header.wrappingClass\">\n <div class=\"row\">\n <div [ngClass]=\"header.parentRowLogoClasses\">\n <img [src]=\"header.logo.src\" [alt]=\"header.logo.alt\" [ngClass]=\"header.logo.imageClassNames\" />\n </div>\n <div [ngClass]=\"header.parentNavItemsClasses\">\n <ez-nav-nav-drawer (drawerPosition)=\"handleDrawerStatus($event)\" [navRow]=\"header.navRow\"></ez-nav-nav-drawer>\n </div>\n </div>\n <div *ngIf=\"isDrawerOpen\">\n <ng-container *ngFor=\"let link of header.navRow.items; let i = index\">\n <div class=\"col-md-12 col-sm-12\" (click)=\"toggleSubNav(i); $event.preventDefault(); $event.stopPropagation();\">\n <a [ngClass]=\"link.anchorTagClassMobile\" [routerLink]=\"link.route\">\n {{ link.title }}\n <ng-container *ngIf=\"link.subNav?.length\">\n <i\n class=\"bi\"\n [ngClass]=\"subNavsOpen[i] ? link.subNavOpenClasses : link.subNavCloseClasses\">\n </i>\n </ng-container>\n </a>\n </div>\n <ng-container *ngIf=\"subNavsOpen[i] && link.subNav?.length\">\n <div class=\"row\">\n <a *ngFor=\"let sub of link.subNav\" [routerLink]=\"sub.route\" [ngClass]=\"sub.cssClasses\">\n {{ sub.title }}\n </a>\n </div>\n </ng-container>\n </ng-container>\n </div>\n</div>\n" }]
}], propDecorators: { header: [{
type: Input
}] } });
class NavbarModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: NavbarModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.9", ngImport: i0, type: NavbarModule, imports: [CommonModule, RouterModule, EzNavComponent, NavDrawerComponent], exports: [EzNavComponent, NavDrawerComponent] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: NavbarModule, imports: [CommonModule, RouterModule, EzNavComponent, NavDrawerComponent] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: NavbarModule, decorators: [{
type: NgModule,
args: [{
declarations: [],
imports: [CommonModule, RouterModule, EzNavComponent, NavDrawerComponent],
exports: [EzNavComponent, NavDrawerComponent]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { EzNavComponent, NavDrawerComponent, NavbarModule, ScreenSizeService };
//# sourceMappingURL=ez-nav.mjs.map