Add new components, styles, and services for user management and navigation

This commit is contained in:
liosha84
2025-06-25 13:50:14 +03:00
parent 13a8ff4494
commit 5dc79438b7
42 changed files with 1439 additions and 0 deletions
@@ -0,0 +1,43 @@
@for (breadcrumb of navigationList; track breadcrumb; let last = $last) {
@if (last && breadcrumb.breadcrumbs !== false) {
<div class="page-header">
<div class="page-block">
<div class="row align-items-center">
<div class="col-md-12">
<ul class="breadcrumb">
<li class="breadcrumb-item">
@if (type === 'theme2') {
<a [routerLink]="['/main/home']" title="Home" class="home"><i class="feather icon-home"></i></a>
}
@if (type === 'theme1') {
<a [routerLink]="['/main/home']" class="home">Home</a>
}
</li>
@for (breadcrumb of navigationList; track breadcrumb) {
@if (breadcrumb.url !== false) {
<li class="breadcrumb-item">
<a [routerLink]="breadcrumb.url" class="f-14 f-w-600">{{ breadcrumb.title }}</a>
</li>
}
@if (breadcrumb.url === false && breadcrumb.type !== 'group') {
<li class="breadcrumb-item">
<a href="javascript:">{{ breadcrumb.title }}</a>
</li>
}
}
</ul>
</div>
<div class="col-md-12">
<div class="page-header-title">
@for (breadcrumb of navigationList; track breadcrumb; let last = $last) {
@if (last) {
<h2 class="mb-0 f-w-600 mt-2">{{ breadcrumb.title }}</h2>
}
}
</div>
</div>
</div>
</div>
</div>
}
}
@@ -0,0 +1,103 @@
// Angular Import
import { Component, Input, inject, input } from '@angular/core';
import { CommonModule } from '@angular/common';
import { NavigationEnd, Router, RouterModule, Event } from '@angular/router';
import { Title } from '@angular/platform-browser';
// project import
//import { NavigationItem, NavigationItems } from 'src/app/theme/layouts/admin-layout/navigation/navigation';
// icons
import { IconService } from '@ant-design/icons-angular';
import { GlobalOutline, NodeExpandOutline } from '@ant-design/icons-angular/icons';
import {NavigationItem, NavigationItems} from '../../layouts/admin-layout/navigation/navigation';
interface titleType {
// eslint-disable-next-line
url: any;
title: string;
breadcrumbs: unknown;
type: string;
link?: string | undefined;
description?: string | undefined;
path?: string | undefined;
}
@Component({
selector: 'app-breadcrumb',
imports: [CommonModule, RouterModule],
templateUrl: './breadcrumb.component.html',
styleUrls: ['./breadcrumb.component.scss']
})
export class BreadcrumbComponent {
private route = inject(Router);
private titleService = inject(Title);
private iconService = inject(IconService);
// public props
@Input() type: string;
dashboard = input(true);
Component = input(false);
navigations: NavigationItem[];
ComponentNavigations: NavigationItem[] = [];
breadcrumbList: Array<string> = [];
navigationList!: titleType[];
componentList!: titleType[];
// constructor
constructor() {
this.navigations = NavigationItems;
this.type = 'theme1';
this.setBreadcrumb();
this.iconService.addIcon(...[GlobalOutline, NodeExpandOutline]);
}
// public method
setBreadcrumb() {
this.route.events.subscribe((router: Event) => {
if (router instanceof NavigationEnd) {
const activeLink = router.url;
const breadcrumbList = this.filterNavigation(this.navigations, activeLink);
this.navigationList = breadcrumbList;//breadcrumbList.slice(breadcrumbList.length - 1, breadcrumbList.length);
const title = breadcrumbList[breadcrumbList.length - 1]?.title || 'Welcome';
this.titleService.setTitle(title + ' | Mantis Angular Admin Template');
}
});
}
filterNavigation(navItems: NavigationItem[], activeLink: string): titleType[] {
for (const navItem of navItems) {
if (navItem.type === 'item' && 'url' in navItem && navItem.url === activeLink) {
return [
{
url: 'url' in navItem ? navItem.url : false,
title: navItem.title,
link: navItem.link,
description: navItem.description,
path: navItem.path,
breadcrumbs: 'breadcrumbs' in navItem ? navItem.breadcrumbs : true,
type: navItem.type
}
];
}
if ((navItem.type === 'group' || navItem.type === 'collapse') && 'children' in navItem) {
const breadcrumbList = this.filterNavigation(navItem.children!, activeLink);
if (breadcrumbList.length > 0) {
breadcrumbList.unshift({
url: 'url' in navItem ? navItem.url : false,
title: navItem.title,
link: navItem.link,
path: navItem.path,
description: navItem.description,
breadcrumbs: 'breadcrumbs' in navItem ? navItem.breadcrumbs : true,
type: navItem.type
});
return breadcrumbList;
}
}
}
return [];
}
}
@@ -0,0 +1,64 @@
.sk-line-material {
top: 0;
position: relative;
margin: auto;
width: 100%;
}
.sk-line-material .sk-child {
width: 100%;
height: 4px;
position: absolute;
top: 0;
display: inline-block;
transform-origin: 0% 0%;
-webkit-animation: sk-line-material 2s ease-in-out 0s infinite both;
animation: sk-line-material 2s ease-in-out 0s infinite both;
}
@-webkit-keyframes sk-line-material {
0%,
80%,
100% {
-webkit-transform: scaleX(0);
transform: scaleX(0);
}
40% {
-webkit-transform: scaleX(1);
transform: scaleX(1);
}
}
@keyframes sk-line-material {
0% {
-webkit-transform: scaleX(0);
transform: scaleX(0);
}
100% {
-webkit-transform: scaleX(1);
transform: scaleX(1);
}
}
#http-loader {
top: 0;
left: 0;
height: 100%;
width: 100%;
position: fixed;
z-index: 9999;
}
.loader-bg {
height: 100%;
width: 100%;
position: absolute;
filter: alpha(opacity=70);
opacity: 1;
background-color: rgba(0, 0, 0, 0);
}
.colored-parent,
.colored > div {
background-color: rgba(26, 188, 156, 0.8);
}
@@ -0,0 +1,11 @@
export const Spinkit = {
skChasingDots: 'sk-chasing-dots',
skCubeGrid: 'sk-cube-grid',
skDoubleBounce: 'sk-double-bounce',
skRotatingPlane: 'sk-rotationg-plane',
skSpinnerPulse: 'sk-spinner-pulse',
skThreeBounce: 'sk-three-bounce',
skWanderingCubes: 'sk-wandering-cubes',
skWave: 'sk-wave',
skLine: 'sk-line-material'
};
@@ -0,0 +1,11 @@
@if (isSpinnerVisible) {
<div id="http-loader">
<div class="loader-bg">
@if (spinner() === Spinkit.skLine) {
<div class="sk-line-material" [class.colored]="!backgroundColor()">
<div class="sk-child sk-bounce1" [style.background-color]="backgroundColor()"></div>
</div>
}
</div>
</div>
}
@@ -0,0 +1,22 @@
#http-loader {
top: 0;
left: 0;
height: 100%;
width: 100%;
position: fixed;
z-index: 9999;
}
.loader-bg {
height: 100%;
width: 100%;
position: absolute;
filter: alpha(opacity=70);
opacity: 0.7;
background-color: #f1f1f1;
}
.colored-parent,
.colored > div {
background-color: #333;
}
@@ -0,0 +1,46 @@
// Angular import
import { Component, OnDestroy, ViewEncapsulation, inject, input } from '@angular/core';
import { Router, NavigationStart, NavigationEnd, NavigationCancel, NavigationError } from '@angular/router';
import { DOCUMENT } from '@angular/common';
// project import
import { Spinkit } from './spinkits';
@Component({
selector: 'app-spinner',
templateUrl: './spinner.component.html',
styleUrls: ['./spinner.component.scss', './spinkit-css/sk-line-material.scss'],
encapsulation: ViewEncapsulation.None
})
export class SpinnerComponent implements OnDestroy {
private router = inject(Router);
private document = inject<Document>(DOCUMENT);
// public props
isSpinnerVisible = true;
Spinkit = Spinkit;
backgroundColor = input('#1890ff');
spinner = input(Spinkit.skLine);
// Constructor
constructor() {
this.router.events.subscribe(
(event) => {
if (event instanceof NavigationStart) {
this.isSpinnerVisible = true;
} else if (event instanceof NavigationEnd || event instanceof NavigationCancel || event instanceof NavigationError) {
this.isSpinnerVisible = false;
}
},
() => {
this.isSpinnerVisible = false;
}
);
}
// life cycle event
ngOnDestroy(): void {
this.isSpinnerVisible = false;
}
}