@@ -41,3 +41,5 @@ out/
|
|||||||
/gradle/
|
/gradle/
|
||||||
/src/main/resources/public/
|
/src/main/resources/public/
|
||||||
/logs/application.log
|
/logs/application.log
|
||||||
|
/logs/
|
||||||
|
/.idea/
|
||||||
|
|||||||
+16
-14
@@ -19,8 +19,7 @@
|
|||||||
"options": {
|
"options": {
|
||||||
"browser": "src/main.ts",
|
"browser": "src/main.ts",
|
||||||
"polyfills": [
|
"polyfills": [
|
||||||
"zone.js",
|
"zone.js"
|
||||||
"@angular/localize/init"
|
|
||||||
],
|
],
|
||||||
"tsConfig": "tsconfig.app.json",
|
"tsConfig": "tsconfig.app.json",
|
||||||
"inlineStyleLanguage": "scss",
|
"inlineStyleLanguage": "scss",
|
||||||
@@ -28,15 +27,22 @@
|
|||||||
{
|
{
|
||||||
"glob": "**/*",
|
"glob": "**/*",
|
||||||
"input": "public"
|
"input": "public"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glob": "**/*",
|
||||||
|
"input": "src/assets/",
|
||||||
|
"output": "/assets/"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
{
|
"@angular/material/prebuilt-themes/azure-blue.css",
|
||||||
"input": "node_modules/@progress/kendo-theme-default/dist/all.css"
|
|
||||||
},
|
|
||||||
"@angular/material/prebuilt-themes/cyan-orange.css",
|
|
||||||
"src/styles.scss"
|
"src/styles.scss"
|
||||||
]
|
],
|
||||||
|
"server": "src/main.server.ts",
|
||||||
|
"outputMode": "server",
|
||||||
|
"ssr": {
|
||||||
|
"entry": "src/server.ts"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
@@ -44,7 +50,7 @@
|
|||||||
{
|
{
|
||||||
"type": "initial",
|
"type": "initial",
|
||||||
"maximumWarning": "500kB",
|
"maximumWarning": "500kB",
|
||||||
"maximumError": "5MB"
|
"maximumError": "1MB"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "anyComponentStyle",
|
"type": "anyComponentStyle",
|
||||||
@@ -82,8 +88,7 @@
|
|||||||
"options": {
|
"options": {
|
||||||
"polyfills": [
|
"polyfills": [
|
||||||
"zone.js",
|
"zone.js",
|
||||||
"zone.js/testing",
|
"zone.js/testing"
|
||||||
"@angular/localize/init"
|
|
||||||
],
|
],
|
||||||
"tsConfig": "tsconfig.spec.json",
|
"tsConfig": "tsconfig.spec.json",
|
||||||
"inlineStyleLanguage": "scss",
|
"inlineStyleLanguage": "scss",
|
||||||
@@ -94,10 +99,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
{
|
"@angular/material/prebuilt-themes/azure-blue.css",
|
||||||
"input": "node_modules/@progress/kendo-theme-default/dist/all.css"
|
|
||||||
},
|
|
||||||
"@angular/material/prebuilt-themes/cyan-orange.css",
|
|
||||||
"src/styles.scss"
|
"src/styles.scss"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+284
-1170
File diff suppressed because it is too large
Load Diff
@@ -11,43 +11,24 @@
|
|||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^20.0.3",
|
"@angular/animations": "^20.0.4",
|
||||||
"@angular/cdk": "^20.0.3",
|
"@angular/cdk": "^20.0.3",
|
||||||
"@angular/common": "^20.0.0",
|
"@angular/common": "^20.0.0",
|
||||||
"@angular/compiler": "^20.0.0",
|
"@angular/compiler": "^20.0.0",
|
||||||
"@angular/core": "^20.0.0",
|
"@angular/core": "^20.0.0",
|
||||||
"@angular/forms": "^20.0.0",
|
"@angular/forms": "^20.0.0",
|
||||||
"@angular/localize": "^20.0.0",
|
|
||||||
"@angular/material": "^20.0.3",
|
"@angular/material": "^20.0.3",
|
||||||
"@angular/platform-browser": "^20.0.0",
|
"@angular/platform-browser": "^20.0.0",
|
||||||
"@angular/platform-browser-dynamic": "^20.0.3",
|
|
||||||
"@angular/platform-server": "^20.0.0",
|
"@angular/platform-server": "^20.0.0",
|
||||||
"@angular/router": "^20.0.0",
|
"@angular/router": "^20.0.0",
|
||||||
"@angular/ssr": "^20.0.2",
|
"@angular/ssr": "^20.0.2",
|
||||||
|
"@ant-design/icons-angular": "19.0.0",
|
||||||
|
"@ng-bootstrap/ng-bootstrap": "19.0.0",
|
||||||
|
"@popperjs/core": "2.11.8",
|
||||||
"@primeng/themes": "^19.1.3",
|
"@primeng/themes": "^19.1.3",
|
||||||
"@progress/kendo-angular-buttons": "19.1.1",
|
"bootstrap": "5.3.6",
|
||||||
"@progress/kendo-angular-common": "19.1.1",
|
|
||||||
"@progress/kendo-angular-dialog": "19.1.1",
|
|
||||||
"@progress/kendo-angular-dropdowns": "19.1.1",
|
|
||||||
"@progress/kendo-angular-editor": "^19.1.1",
|
|
||||||
"@progress/kendo-angular-icons": "19.1.1",
|
|
||||||
"@progress/kendo-angular-indicators": "^19.1.1",
|
|
||||||
"@progress/kendo-angular-inputs": "19.1.1",
|
|
||||||
"@progress/kendo-angular-intl": "19.1.1",
|
|
||||||
"@progress/kendo-angular-l10n": "19.1.1",
|
|
||||||
"@progress/kendo-angular-label": "19.1.1",
|
|
||||||
"@progress/kendo-angular-layout": "19.1.1",
|
|
||||||
"@progress/kendo-angular-navigation": "19.1.1",
|
|
||||||
"@progress/kendo-angular-popup": "19.1.1",
|
|
||||||
"@progress/kendo-angular-progressbar": "19.1.1",
|
|
||||||
"@progress/kendo-angular-toolbar": "19.1.1",
|
|
||||||
"@progress/kendo-angular-treeview": "19.1.1",
|
|
||||||
"@progress/kendo-angular-utils": "^19.1.1",
|
|
||||||
"@progress/kendo-drawing": "^1.21.0",
|
|
||||||
"@progress/kendo-licensing": "^1.5.0",
|
|
||||||
"@progress/kendo-svg-icons": "^4.0.0",
|
|
||||||
"@progress/kendo-theme-default": "11.0.2",
|
|
||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
|
"ngx-scrollbar": "18.0.0",
|
||||||
"primeng": "^19.1.3",
|
"primeng": "^19.1.3",
|
||||||
"rxjs": "~7.8.0",
|
"rxjs": "~7.8.0",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p><p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p><p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p><p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
<p>admin-welcome.component works!</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AdminWelcomeComponent } from './admin-welcome.component';
|
||||||
|
|
||||||
|
describe('AdminWelcomeComponent', () => {
|
||||||
|
let component: AdminWelcomeComponent;
|
||||||
|
let fixture: ComponentFixture<AdminWelcomeComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [AdminWelcomeComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(AdminWelcomeComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-admin-welcome.component',
|
||||||
|
imports: [],
|
||||||
|
templateUrl: './admin-welcome.component.html',
|
||||||
|
styleUrl: './admin-welcome.component.scss'
|
||||||
|
})
|
||||||
|
export class AdminWelcomeComponent {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<!--<p>admin.component works!</p>-->
|
||||||
|
|
||||||
|
<app-navigation
|
||||||
|
class="pc-sidebar"
|
||||||
|
[ngClass]="{
|
||||||
|
'navbar-collapsed': navCollapsed,
|
||||||
|
'mob-open': navCollapsedMob
|
||||||
|
}"
|
||||||
|
(NavCollapse)="this.navCollapsed = !this.navCollapsed"
|
||||||
|
/>
|
||||||
|
<app-nav-bar (NavCollapsedMob)="navMobClick()" (NavCollapse)="this.navCollapsed = !this.navCollapsed"/>
|
||||||
|
<div class="pc-container">
|
||||||
|
<div class="coded-wrapper">
|
||||||
|
<div class="coded-content">
|
||||||
|
<div class="coded-inner-content">
|
||||||
|
<app-breadcrumb />
|
||||||
|
<div class="main-body">
|
||||||
|
<div class="page-wrapper">
|
||||||
|
<router-outlet />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pc-menu-overlay" (click)="closeMenu()" (keydown)="handleKeyDown($event)" tabindex="0"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--<div class="pc-container">
|
||||||
|
<div class="coded-wrapper">
|
||||||
|
<div class="coded-content">
|
||||||
|
<div class="coded-inner-content">
|
||||||
|
<app-breadcrumb />
|
||||||
|
<div class="main-body">
|
||||||
|
<div class="page-wrapper">
|
||||||
|
<router-outlet></router-outlet>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pc-menu-overlay" (click)="closeMenu()" (keydown)="handleKeyDown($event)" tabindex="0"></div>
|
||||||
|
</div>-->
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
.example-container {
|
||||||
|
width: 500px;
|
||||||
|
height: 300px;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-sidenav-content {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-sidenav {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pc-sidebar{
|
||||||
|
top: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AdminComponent } from './admin.component';
|
||||||
|
|
||||||
|
describe('AdminComponent', () => {
|
||||||
|
let component: AdminComponent;
|
||||||
|
let fixture: ComponentFixture<AdminComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [AdminComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(AdminComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
import {Component, CUSTOM_ELEMENTS_SCHEMA, inject, OnInit} from '@angular/core';
|
||||||
|
import {BreadcrumbComponent} from "../../components/breadcrumb/breadcrumb.component";
|
||||||
|
import {NavBarComponent} from "../../layouts/admin-layout/nav-bar/nav-bar.component";
|
||||||
|
import {NavigationComponent} from "../../layouts/admin-layout/navigation/navigation.component";
|
||||||
|
import {Router, RouterLink, RouterOutlet} from "@angular/router";
|
||||||
|
import {DOCUMENT, NgClass, NgStyle} from '@angular/common';
|
||||||
|
import {MatDrawerContainer, MatSidenavModule} from '@angular/material/sidenav';
|
||||||
|
import {MatButton} from '@angular/material/button';
|
||||||
|
import { ScrollPanelModule } from 'primeng/scrollpanel';
|
||||||
|
import {MenuItem} from 'primeng/api';
|
||||||
|
import {PanelMenu} from 'primeng/panelmenu';
|
||||||
|
@Component({
|
||||||
|
selector: 'app-admin.component',
|
||||||
|
imports: [
|
||||||
|
BreadcrumbComponent,
|
||||||
|
NavBarComponent,
|
||||||
|
NavigationComponent,
|
||||||
|
RouterOutlet,
|
||||||
|
NgClass,
|
||||||
|
MatDrawerContainer,
|
||||||
|
MatSidenavModule,
|
||||||
|
ScrollPanelModule,
|
||||||
|
MatButton,
|
||||||
|
RouterLink,
|
||||||
|
PanelMenu,
|
||||||
|
NgStyle,
|
||||||
|
|
||||||
|
],
|
||||||
|
schemas:[CUSTOM_ELEMENTS_SCHEMA],
|
||||||
|
templateUrl: './admin.component.html',
|
||||||
|
styleUrl: './admin.component.scss'
|
||||||
|
})
|
||||||
|
export class AdminComponent implements OnInit {
|
||||||
|
private document = inject<Document>(DOCUMENT);
|
||||||
|
height = 0;
|
||||||
|
|
||||||
|
items: MenuItem[] | undefined;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(private router: Router) {
|
||||||
|
this.height = 0
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// public props
|
||||||
|
navCollapsed: boolean = false;
|
||||||
|
navCollapsedMob: boolean = false;
|
||||||
|
|
||||||
|
// public method
|
||||||
|
navMobClick() {
|
||||||
|
if (this.navCollapsedMob && !document.querySelector('app-navigation.pc-sidebar')?.classList.contains('mob-open')) {
|
||||||
|
this.navCollapsedMob = !this.navCollapsedMob;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.navCollapsedMob = !this.navCollapsedMob;
|
||||||
|
}, 100);
|
||||||
|
} else {
|
||||||
|
this.navCollapsedMob = !this.navCollapsedMob;
|
||||||
|
}
|
||||||
|
if (document.querySelector('app-navigation.pc-sidebar')?.classList.contains('navbar-collapsed')) {
|
||||||
|
document.querySelector('app-navigation.pc-sidebar')?.classList.remove('navbar-collapsed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyDown(event: KeyboardEvent): void {
|
||||||
|
if (event.key === 'Escape') {
|
||||||
|
this.closeMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closeMenu() {
|
||||||
|
if (document.querySelector('app-navigation.pc-sidebar')?.classList.contains('mob-open')) {
|
||||||
|
document.querySelector('app-navigation.pc-sidebar')?.classList.remove('mob-open');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
|
||||||
|
if(this.document.defaultView !== null || this.document.defaultView !== undefined) {
|
||||||
|
// @ts-ignore
|
||||||
|
this.height = this.document.defaultView.innerHeight;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
this.height = 0;
|
||||||
|
|
||||||
|
this.items = [
|
||||||
|
{
|
||||||
|
label: 'Admin',
|
||||||
|
icon: 'pi pi-palette',
|
||||||
|
command: () => {
|
||||||
|
this.router.navigate(['/main/admin/welcome']);
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: 'Settings',
|
||||||
|
icon: 'pi pi-eraser',
|
||||||
|
// route: '/main/admin/settings'
|
||||||
|
command: () => {
|
||||||
|
this.router.navigate(['/main/admin/settings']);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'System',
|
||||||
|
icon: 'pi pi-heart',
|
||||||
|
route: '/main/admin/system'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import {CUSTOM_ELEMENTS_SCHEMA, NgModule} from '@angular/core';
|
||||||
|
import {mainRouting} from '../main-module/main.routing';
|
||||||
|
import {MainComponent} from '../main-module/main.component/main.component';
|
||||||
|
import {RouterModule} from '@angular/router';
|
||||||
|
import {AdminComponent} from './admin.component/admin.component';
|
||||||
|
import {adminRouting} from './admin.routing';
|
||||||
|
import { ScrollPanelModule } from 'primeng/scrollpanel';
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
|
||||||
|
],
|
||||||
|
imports: [adminRouting, AdminComponent,ScrollPanelModule],
|
||||||
|
exports: [RouterModule],
|
||||||
|
schemas:[CUSTOM_ELEMENTS_SCHEMA]
|
||||||
|
})
|
||||||
|
export class AdminModule {}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import {RouterModule, Routes} from '@angular/router';
|
||||||
|
import {AdminComponent} from './admin.component/admin.component';
|
||||||
|
|
||||||
|
const ADMIN_ROUTES: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: AdminComponent,
|
||||||
|
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'welcome',
|
||||||
|
loadComponent: () => import('../admin-module/admin-welcome.component/admin-welcome.component').then((c) => c.AdminWelcomeComponent),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'settings',
|
||||||
|
loadComponent: () => import('../admin-module/settings.component/settings.component').then((c) => c.SettingsComponent)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'system',
|
||||||
|
|
||||||
|
loadComponent: () => import('../admin-module/system.component/system.component').then((c) => c.SystemComponent)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export const adminRouting = RouterModule.forChild(ADMIN_ROUTES);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<p>settings.component works!</p>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { SettingsComponent } from './settings.component';
|
||||||
|
|
||||||
|
describe('SettingsComponent', () => {
|
||||||
|
let component: SettingsComponent;
|
||||||
|
let fixture: ComponentFixture<SettingsComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [SettingsComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(SettingsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-settings.component',
|
||||||
|
imports: [],
|
||||||
|
templateUrl: './settings.component.html',
|
||||||
|
styleUrl: './settings.component.scss'
|
||||||
|
})
|
||||||
|
export class SettingsComponent {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
<mat-card>
|
||||||
|
<mat-card-content>
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
<mat-tab-group>
|
||||||
|
<mat-tab label="Custom beans">
|
||||||
|
Content 1
|
||||||
|
<table mat-table
|
||||||
|
[dataSource]="customBeans" multiTemplateDataRows="true" class="mat-elevation-z8">
|
||||||
|
@for (column of displayedColumns; track column) {
|
||||||
|
<ng-container matColumnDef="{{column}}">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>{{column}}</th>
|
||||||
|
<td mat-cell *matCellDef="let element ; let k = dataIndex;">{{element[column]}}</td>
|
||||||
|
</ng-container>
|
||||||
|
}
|
||||||
|
<ng-container matColumnDef="expand">
|
||||||
|
<th mat-header-cell *matHeaderCellDef aria-label="row actions"> </th>
|
||||||
|
<td mat-cell *matCellDef="let element">
|
||||||
|
<button
|
||||||
|
matIconButton
|
||||||
|
aria-label="expand row"
|
||||||
|
(click)="toggle(element); $event.stopPropagation()"
|
||||||
|
class="example-toggle-button"
|
||||||
|
[class.example-toggle-button-expanded]="isExpanded(element)">
|
||||||
|
<mat-icon>keyboard_arrow_down</mat-icon>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->
|
||||||
|
<ng-container matColumnDef="expandedDetail">
|
||||||
|
<td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplayWithExpand.length">
|
||||||
|
<div class="example-element-detail-wrapper"
|
||||||
|
[class.example-element-detail-wrapper-expanded]="isExpanded(element)">
|
||||||
|
<div class="example-element-detail">
|
||||||
|
|
||||||
|
<mat-list role="list">
|
||||||
|
<mat-list-item role="listitem">Name: {{element.name}}</mat-list-item>
|
||||||
|
<mat-list-item role="listitem">Type: {{element.type}}</mat-list-item>
|
||||||
|
</mat-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="columnsToDisplayWithExpand"></tr>
|
||||||
|
<tr mat-row *matRowDef="let element; columns: columnsToDisplayWithExpand;"
|
||||||
|
class="example-element-row"
|
||||||
|
[class.example-expanded-row]="isExpanded(element)"
|
||||||
|
(click)="toggle(element)">
|
||||||
|
</tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="All beans">
|
||||||
|
Content 2
|
||||||
|
<table mat-table
|
||||||
|
[dataSource]="allBeans" multiTemplateDataRows="true" class="mat-elevation-z8">
|
||||||
|
@for (column of displayedColumns; track column) {
|
||||||
|
<ng-container matColumnDef="{{column}}">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>{{column}}</th>
|
||||||
|
<td mat-cell *matCellDef="let element ; let k = dataIndex;">{{element[column]}}</td>
|
||||||
|
</ng-container>
|
||||||
|
}
|
||||||
|
<ng-container matColumnDef="expand">
|
||||||
|
<th mat-header-cell *matHeaderCellDef aria-label="row actions"> </th>
|
||||||
|
<td mat-cell *matCellDef="let element">
|
||||||
|
<button
|
||||||
|
matIconButton
|
||||||
|
aria-label="expand row"
|
||||||
|
(click)="toggle(element); $event.stopPropagation()"
|
||||||
|
class="example-toggle-button"
|
||||||
|
[class.example-toggle-button-expanded]="isExpanded(element)">
|
||||||
|
<mat-icon>keyboard_arrow_down</mat-icon>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->
|
||||||
|
<ng-container matColumnDef="expandedDetail">
|
||||||
|
<td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplayWithExpand.length">
|
||||||
|
<div class="example-element-detail-wrapper"
|
||||||
|
[class.example-element-detail-wrapper-expanded]="isExpanded(element)">
|
||||||
|
<div class="example-element-detail">
|
||||||
|
|
||||||
|
<mat-list role="list">
|
||||||
|
<mat-list-item role="listitem">Name: {{element.name}}</mat-list-item>
|
||||||
|
<mat-list-item role="listitem">Type: {{element.type}}</mat-list-item>
|
||||||
|
</mat-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="columnsToDisplayWithExpand"></tr>
|
||||||
|
<tr mat-row *matRowDef="let element; columns: columnsToDisplayWithExpand;"
|
||||||
|
class="example-element-row"
|
||||||
|
[class.example-expanded-row]="isExpanded(element)"
|
||||||
|
(click)="toggle(element)">
|
||||||
|
</tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
|
||||||
|
</table>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
mat-card{
|
||||||
|
//margin: 20px;
|
||||||
|
background-color: rgba(240, 248, 255, 0.7);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-card-title{
|
||||||
|
color: cyan;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-card-subtitle{
|
||||||
|
color: #009dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-tab{
|
||||||
|
color:black;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 20px;
|
||||||
|
color:lightgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mat-list{
|
||||||
|
//background-color: #1389d3;
|
||||||
|
color:black;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-list-item{
|
||||||
|
margin: 10px 10px 10px 10px;
|
||||||
|
background-color: #447694;
|
||||||
|
|
||||||
|
color: #009dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.example-detail-row {
|
||||||
|
height: 0;
|
||||||
|
background: #fffdfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.example-element-row {
|
||||||
|
cursor: pointer;
|
||||||
|
color: #1389d3;
|
||||||
|
background: #fffdfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.example-element-row:not(.example-expanded-row):hover {
|
||||||
|
background: whitesmoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.example-element-row:not(.example-expanded-row):active {
|
||||||
|
background: #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-row td {
|
||||||
|
border-bottom-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-detail-wrapper {
|
||||||
|
overflow: hidden;
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: 0fr;
|
||||||
|
grid-template-columns: 100%;
|
||||||
|
transition: grid-template-rows 225ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-detail-wrapper-expanded {
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-detail {
|
||||||
|
display: flex;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-diagram {
|
||||||
|
min-width: 80px;
|
||||||
|
border: 2px solid black;
|
||||||
|
padding: 8px;
|
||||||
|
font-weight: lighter;
|
||||||
|
margin: 8px 0;
|
||||||
|
height: 104px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-symbol {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 40px;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-description {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-description-attribution {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-toggle-button {
|
||||||
|
transition: transform 225ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-toggle-button-expanded {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { SystemComponent } from './system.component';
|
||||||
|
|
||||||
|
describe('SystemComponent', () => {
|
||||||
|
let component: SystemComponent;
|
||||||
|
let fixture: ComponentFixture<SystemComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [SystemComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(SystemComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
||||||
|
import {MatCard, MatCardContent, MatCardHeader} from '@angular/material/card';
|
||||||
|
import {MatDivider} from '@angular/material/divider';
|
||||||
|
import {MatTab, MatTabGroup} from '@angular/material/tabs';
|
||||||
|
import {
|
||||||
|
MatCell,
|
||||||
|
MatCellDef,
|
||||||
|
MatColumnDef,
|
||||||
|
MatHeaderCell, MatHeaderCellDef,
|
||||||
|
MatHeaderRow, MatHeaderRowDef,
|
||||||
|
MatRow,
|
||||||
|
MatRowDef,
|
||||||
|
MatTable
|
||||||
|
} from '@angular/material/table';
|
||||||
|
import {MatList, MatListItem} from '@angular/material/list';
|
||||||
|
import {MatIconButton} from '@angular/material/button';
|
||||||
|
import {SystemService} from '../../services/system.service';
|
||||||
|
import {Bean} from '../../models/Bean';
|
||||||
|
import {MatIcon} from '@angular/material/icon';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-system.component',
|
||||||
|
imports: [
|
||||||
|
MatCard,
|
||||||
|
MatCardHeader,
|
||||||
|
MatCardContent,
|
||||||
|
MatDivider,
|
||||||
|
MatTabGroup,
|
||||||
|
MatTab,
|
||||||
|
MatTable,
|
||||||
|
MatColumnDef,
|
||||||
|
MatIcon,
|
||||||
|
MatCell,
|
||||||
|
MatCellDef,
|
||||||
|
MatList,
|
||||||
|
MatListItem,
|
||||||
|
MatRow,
|
||||||
|
MatHeaderRow,
|
||||||
|
MatRowDef,
|
||||||
|
MatHeaderCell,
|
||||||
|
MatHeaderCellDef,
|
||||||
|
MatIconButton,
|
||||||
|
MatIcon,
|
||||||
|
MatHeaderRowDef
|
||||||
|
],
|
||||||
|
templateUrl: './system.component.html',
|
||||||
|
styleUrl: './system.component.scss',
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||||
|
})
|
||||||
|
export class SystemComponent {
|
||||||
|
customBeans:Bean[] = [] ;
|
||||||
|
allBeans:Bean[] = [] ;
|
||||||
|
displayedColumns: string[] = ['shortName', 'typeShortName', 'scope'];
|
||||||
|
|
||||||
|
columnsToDisplayWithExpand = [...this.displayedColumns, 'expand'];
|
||||||
|
|
||||||
|
expandedElement: Bean | null = null;
|
||||||
|
|
||||||
|
resultsLength = 0;
|
||||||
|
isLoadingResults = true;
|
||||||
|
isRateLimitReached = false;
|
||||||
|
|
||||||
|
constructor(private systemService: SystemService) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.retrieveBeans();
|
||||||
|
}
|
||||||
|
|
||||||
|
retrieveBeans(): void {
|
||||||
|
this.systemService.getCustomBeans()
|
||||||
|
.subscribe(
|
||||||
|
(data: Bean[]) => {
|
||||||
|
this.customBeans = data;
|
||||||
|
console.log(data);
|
||||||
|
},
|
||||||
|
(error: any) => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
this.systemService.getAllBeans()
|
||||||
|
.subscribe(
|
||||||
|
(data: Bean[]) => {
|
||||||
|
this.allBeans = data;
|
||||||
|
console.log(data);
|
||||||
|
},
|
||||||
|
(error: any) => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks whether an element is expanded. */
|
||||||
|
isExpanded(element: Bean) {
|
||||||
|
return this.expandedElement === element;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Toggles the expanded state of an element. */
|
||||||
|
toggle(element: Bean) {
|
||||||
|
this.expandedElement = this.isExpanded(element) ? null : element;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//ngAfterViewInit() {
|
||||||
|
//this.exampleDatabase = new ExampleHttpDatabase(this._httpClient);
|
||||||
|
|
||||||
|
// If the user changes the sort order, reset back to the first page.
|
||||||
|
/* this.sort.sortChange.subscribe(() => (this.paginator.pageIndex = 0));
|
||||||
|
|
||||||
|
merge(this.sort.sortChange, this.paginator.page)
|
||||||
|
.pipe(
|
||||||
|
startWith({}),
|
||||||
|
switchMap(() => {
|
||||||
|
this.isLoadingResults = true;
|
||||||
|
return this.exampleDatabase!.getRepoIssues(
|
||||||
|
this.sort.active,
|
||||||
|
this.sort.direction,
|
||||||
|
this.paginator.pageIndex,
|
||||||
|
).pipe(catchError(() => observableOf(null)));
|
||||||
|
}),
|
||||||
|
map(data => {
|
||||||
|
// Flip flag to show that loading has finished.
|
||||||
|
this.isLoadingResults = false;
|
||||||
|
this.isRateLimitReached = data === null;
|
||||||
|
|
||||||
|
if (data === null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only refresh the result length if there is new data. In case of rate
|
||||||
|
// limit errors, we do not want to reset the paginator to zero, as that
|
||||||
|
// would prevent users from re-triggering requests.
|
||||||
|
this.resultsLength = data.total_count;
|
||||||
|
return data.items;
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.subscribe(data => (this.data = data));*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { RouterModule, Routes } from '@angular/router';
|
|
||||||
import { TutorialsListComponent } from './components/tutorials-list/tutorials-list.component';
|
|
||||||
import { TutorialDetailsComponent } from './components/tutorial-details/tutorial-details.component';
|
|
||||||
import { AddTutorialComponent } from './components/add-tutorial/add-tutorial.component';
|
|
||||||
import { BoardAdminComponent } from './components/board-admin/board-admin.component';
|
|
||||||
import { BoardModeratorComponent } from './components/board-moderator/board-moderator.component';
|
|
||||||
import { BoardUserComponent } from './components/board-user/board-user.component';
|
|
||||||
import { ProfileComponent } from './components/profile/profile.component';
|
|
||||||
import { RegisterComponent } from './components/register/register.component';
|
|
||||||
import { LoginComponent } from './components/login/login.component';
|
|
||||||
import { HomeComponent } from './components/home/home.component';
|
|
||||||
import {SystemComponent} from './components/system.component/system.component';
|
|
||||||
|
|
||||||
|
|
||||||
const routes: Routes = [
|
|
||||||
{ path: 'home', component: HomeComponent },
|
|
||||||
{ path: 'login', component: LoginComponent },
|
|
||||||
{ path: 'register', component: RegisterComponent },
|
|
||||||
{ path: 'profile', component: ProfileComponent },
|
|
||||||
{ path: 'user', component: BoardUserComponent },
|
|
||||||
{ path: 'mod', component: BoardModeratorComponent },
|
|
||||||
{ path: 'admin', component: BoardAdminComponent },
|
|
||||||
{ path: '', redirectTo: 'home', pathMatch: 'full' },
|
|
||||||
{ path: 'tutorials', component: TutorialsListComponent },
|
|
||||||
{ path: 'tutorials/:id', component: TutorialDetailsComponent },
|
|
||||||
{ path: 'add', component: AddTutorialComponent },
|
|
||||||
{ path: 'system', component: SystemComponent}
|
|
||||||
];
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [RouterModule.forRoot(routes, {useHash: true})],
|
|
||||||
exports: [RouterModule]
|
|
||||||
})
|
|
||||||
export class AppRoutingModule { }
|
|
||||||
@@ -1,16 +1,27 @@
|
|||||||
import {Component, inject, OnInit} from '@angular/core';
|
import {Component, CUSTOM_ELEMENTS_SCHEMA, inject, OnInit} from '@angular/core';
|
||||||
import { TokenStorageService } from './services/token-storage.service';
|
import { TokenStorageService } from './services/token-storage.service';
|
||||||
import {MatDialog} from "@angular/material/dialog";
|
import {MatDialog} from "@angular/material/dialog";
|
||||||
import {DialogComponent} from "./components/dialog/dialog.component";
|
import {DialogComponent} from "./components/dialog/dialog.component";
|
||||||
import {AuthService} from "./services/auth.service";
|
import {AuthService} from "./services/auth.service";
|
||||||
import {Subscription} from "rxjs";
|
import {Subscription} from "rxjs";
|
||||||
import {EventBusService} from "./_shared/event-bus.service";
|
import {EventBusService} from "./_shared/event-bus.service";
|
||||||
|
import {RouterLink, RouterOutlet} from '@angular/router';
|
||||||
|
import {MatButton} from '@angular/material/button';
|
||||||
|
import {MatToolbar} from '@angular/material/toolbar';
|
||||||
|
import {MatIcon} from '@angular/material/icon';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrls: ['./app.component.scss'],
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
standalone: false
|
imports: [
|
||||||
|
RouterOutlet,
|
||||||
|
MatIcon,
|
||||||
|
MatButton,
|
||||||
|
RouterLink,
|
||||||
|
MatToolbar
|
||||||
|
],
|
||||||
|
styleUrls: ['./app.component.scss']
|
||||||
})
|
})
|
||||||
export class AppComponent implements OnInit {
|
export class AppComponent implements OnInit {
|
||||||
readonly dialog = inject(MatDialog);
|
readonly dialog = inject(MatDialog);
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
|
||||||
|
import { provideServerRendering, withRoutes } from '@angular/ssr';
|
||||||
|
import { appConfig } from './app.config';
|
||||||
|
import { serverRoutes } from './app.routes.server';
|
||||||
|
|
||||||
|
const serverConfig: ApplicationConfig = {
|
||||||
|
providers: [
|
||||||
|
provideServerRendering(withRoutes(serverRoutes))
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export const config = mergeApplicationConfig(appConfig, serverConfig);
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import {
|
||||||
|
ApplicationConfig,
|
||||||
|
importProvidersFrom,
|
||||||
|
provideBrowserGlobalErrorListeners,
|
||||||
|
provideZoneChangeDetection
|
||||||
|
} from '@angular/core';
|
||||||
|
import { provideRouter } from '@angular/router';
|
||||||
|
|
||||||
|
import { routes } from './app.routes';
|
||||||
|
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
|
||||||
|
import {AppModule} from './app.module';
|
||||||
|
import {providePrimeNG} from 'primeng/config';
|
||||||
|
import Aura from '@primeng/themes/aura';
|
||||||
|
|
||||||
|
export const appConfig: ApplicationConfig = {
|
||||||
|
providers: [
|
||||||
|
provideBrowserGlobalErrorListeners(),
|
||||||
|
provideZoneChangeDetection({ eventCoalescing: true }),
|
||||||
|
provideRouter(routes), provideClientHydration(withEventReplay()),
|
||||||
|
|
||||||
|
importProvidersFrom(AppModule),
|
||||||
|
providePrimeNG({
|
||||||
|
theme: {
|
||||||
|
preset: Aura
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<router-outlet></router-outlet>
|
||||||
@@ -1,118 +1,40 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import {CUSTOM_ELEMENTS_SCHEMA, NgModule} from '@angular/core';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule }
|
||||||
|
from '@angular/platform-browser';
|
||||||
|
|
||||||
import { AppRoutingModule } from './app-routing.module';
|
import { BrowserAnimationsModule }
|
||||||
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
|
from '@angular/platform-browser/animations';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import {provideHttpClient, withInterceptorsFromDi} from '@angular/common/http';
|
||||||
import { AppComponent } from './app.component';
|
|
||||||
import { TutorialsListComponent } from './components/tutorials-list/tutorials-list.component';
|
|
||||||
import { TutorialDetailsComponent } from './components/tutorial-details/tutorial-details.component';
|
|
||||||
import { AddTutorialComponent } from './components/add-tutorial/add-tutorial.component';
|
|
||||||
import { LoginComponent } from './components/login/login.component';
|
|
||||||
import { RegisterComponent } from './components/register/register.component';
|
|
||||||
import { HomeComponent } from './components/home/home.component';
|
|
||||||
import { ProfileComponent } from './components/profile/profile.component';
|
|
||||||
import { BoardAdminComponent } from './components/board-admin/board-admin.component';
|
|
||||||
import { BoardModeratorComponent } from './components/board-moderator/board-moderator.component';
|
|
||||||
import { BoardUserComponent } from './components/board-user/board-user.component';
|
|
||||||
|
|
||||||
|
import {MainComponent} from './main-module/main.component/main.component';
|
||||||
import {authInterceptorProviders} from './helpers/auth.interceptor';
|
import {authInterceptorProviders} from './helpers/auth.interceptor';
|
||||||
import {provideHttpClient, withInterceptorsFromDi} from "@angular/common/http";
|
import {AdminComponent} from './admin-module/admin.component/admin.component';
|
||||||
import {provideAnimationsAsync} from "@angular/platform-browser/animations/async";
|
import {AdminWelcomeComponent} from './admin-module/admin-welcome.component/admin-welcome.component';
|
||||||
import {MatToolbar} from "@angular/material/toolbar";
|
import {SettingsComponent} from './admin-module/settings.component/settings.component';
|
||||||
import {MatAnchor, MatButton} from "@angular/material/button";
|
import {SystemComponent} from './admin-module/system.component/system.component';
|
||||||
import {MatIcon} from "@angular/material/icon";
|
import {appRouting} from './app.routes';
|
||||||
import {MatChipGrid, MatChipInput, MatChipListbox, MatChipOption, MatChipRow} from "@angular/material/chips";
|
import {App} from './app';
|
||||||
import {MatAutocomplete, MatAutocompleteTrigger, MatOption} from "@angular/material/autocomplete";
|
|
||||||
import {MatFormField} from "@angular/material/form-field";
|
|
||||||
import {MatLabel} from '@angular/material/form-field';
|
|
||||||
|
|
||||||
|
|
||||||
import {
|
|
||||||
MatCard, MatCardActions,
|
|
||||||
MatCardContent,
|
|
||||||
MatCardHeader,
|
|
||||||
MatCardImage,
|
|
||||||
MatCardSubtitle,
|
|
||||||
MatCardTitle
|
|
||||||
} from '@angular/material/card';
|
|
||||||
import {MatInput} from '@angular/material/input';
|
|
||||||
import {EditorComponent} from '@progress/kendo-angular-editor';
|
|
||||||
import {ArticleComments} from './components/article-comments/article-comments';
|
|
||||||
import {MatProgressSpinner} from '@angular/material/progress-spinner';
|
|
||||||
import {providePrimeNG} from 'primeng/config';
|
|
||||||
import Aura from '@primeng/themes/aura';
|
|
||||||
import {Button} from 'primeng/button';
|
|
||||||
import {ScrollPanelModule} from 'primeng/scrollpanel';
|
|
||||||
import {Splitter} from 'primeng/splitter';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent,
|
|
||||||
TutorialsListComponent,
|
|
||||||
TutorialDetailsComponent,
|
|
||||||
AddTutorialComponent,
|
|
||||||
|
|
||||||
RegisterComponent,
|
|
||||||
HomeComponent,
|
|
||||||
ProfileComponent,
|
|
||||||
BoardAdminComponent,
|
|
||||||
BoardModeratorComponent,
|
|
||||||
BoardUserComponent
|
|
||||||
|
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent],
|
|
||||||
imports: [
|
imports: [
|
||||||
|
appRouting,
|
||||||
|
MainComponent,
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
AppRoutingModule,
|
MatIconModule,
|
||||||
FormsModule,
|
BrowserAnimationsModule,
|
||||||
LoginComponent,
|
AdminComponent,
|
||||||
MatToolbar,
|
AdminWelcomeComponent,
|
||||||
MatButton,
|
SettingsComponent,
|
||||||
MatIcon,
|
SystemComponent
|
||||||
MatAnchor,
|
|
||||||
MatChipGrid,
|
|
||||||
MatChipRow,
|
|
||||||
MatChipInput,
|
|
||||||
MatAutocompleteTrigger,
|
|
||||||
MatAutocomplete,
|
|
||||||
MatOption,
|
|
||||||
MatFormField,
|
|
||||||
MatChipListbox,
|
|
||||||
MatChipOption,
|
|
||||||
ReactiveFormsModule,
|
|
||||||
MatCardContent,
|
|
||||||
MatCardSubtitle,
|
|
||||||
MatCardTitle,
|
|
||||||
MatCard,
|
|
||||||
MatCardHeader,
|
|
||||||
MatCardImage,
|
|
||||||
MatCardActions,
|
|
||||||
MatInput,
|
|
||||||
MatLabel,
|
|
||||||
EditorComponent,
|
|
||||||
ArticleComments,
|
|
||||||
MatProgressSpinner,
|
|
||||||
Button,
|
|
||||||
ScrollPanelModule,
|
|
||||||
Splitter
|
|
||||||
|
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
authInterceptorProviders,
|
authInterceptorProviders,provideHttpClient(withInterceptorsFromDi())],
|
||||||
provideHttpClient(withInterceptorsFromDi()),
|
|
||||||
provideAnimationsAsync(),
|
bootstrap: [],
|
||||||
providePrimeNG({
|
schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
|
||||||
theme: {
|
|
||||||
preset: Aura,
|
|
||||||
options: {darkModeSelector: '.p-dark'}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
] })
|
|
||||||
|
|
||||||
|
|
||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { RenderMode, ServerRoute } from '@angular/ssr';
|
||||||
|
|
||||||
|
export const serverRoutes: ServerRoute[] = [
|
||||||
|
{
|
||||||
|
path: '**',
|
||||||
|
renderMode: RenderMode.Prerender
|
||||||
|
}
|
||||||
|
];
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import {RouterModule, Routes} from '@angular/router';
|
||||||
|
import {AdminComponent} from './layouts/admin-layout/admin-layout.component';
|
||||||
|
import {MainComponent} from './main-module/main.component/main.component';
|
||||||
|
import {NgModule} from '@angular/core';
|
||||||
|
|
||||||
|
export const routes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
redirectTo: 'main/home',
|
||||||
|
pathMatch: 'full'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'main',
|
||||||
|
loadChildren: () =>
|
||||||
|
import('./main-module/main.module').then((m) => m.MainModule),
|
||||||
|
}
|
||||||
|
|
||||||
|
];
|
||||||
|
export const appRouting = RouterModule.forRoot(routes);
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
import { App } from './app';
|
||||||
|
|
||||||
|
describe('App', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [App],
|
||||||
|
}).compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create the app', () => {
|
||||||
|
const fixture = TestBed.createComponent(App);
|
||||||
|
const app = fixture.componentInstance;
|
||||||
|
expect(app).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render title', () => {
|
||||||
|
const fixture = TestBed.createComponent(App);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const compiled = fixture.nativeElement as HTMLElement;
|
||||||
|
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, jambotron-ui');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { RouterOutlet } from '@angular/router';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-root',
|
||||||
|
templateUrl: './app.html',
|
||||||
|
imports: [
|
||||||
|
RouterOutlet
|
||||||
|
],
|
||||||
|
styleUrl: './app.scss'
|
||||||
|
})
|
||||||
|
export class App {
|
||||||
|
protected title = 'jambotron-ui';
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
}
|
||||||
@@ -44,7 +44,8 @@
|
|||||||
<input matInput required
|
<input matInput required
|
||||||
[(ngModel)]="tutorial.title">
|
[(ngModel)]="tutorial.title">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<kendo-editor [(ngModel)]="tutorial.description" ></kendo-editor>
|
<!-- <kendo-editor [(ngModel)]="tutorial.description" ></kendo-editor>-->
|
||||||
|
<textarea matInput required [(ngModel)]="tutorial.description"></textarea>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
<mat-card-actions>
|
<mat-card-actions>
|
||||||
<button matButton (click)="saveTutorial()" *ngIf="!submitted">Save</button>
|
<button matButton (click)="saveTutorial()" *ngIf="!submitted">Save</button>
|
||||||
|
|||||||
@@ -1,12 +1,32 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import {Component, CUSTOM_ELEMENTS_SCHEMA, OnInit} from '@angular/core';
|
||||||
import {Tutorial} from '../../models/tutorial.model';
|
import {Tutorial} from '../../models/tutorial.model';
|
||||||
import {TutorialService} from '../../services/tutorial.service';
|
import {TutorialService} from '../../services/tutorial.service';
|
||||||
|
import {MatCard, MatCardActions, MatCardContent, MatCardHeader} from '@angular/material/card';
|
||||||
|
import {FormsModule} from '@angular/forms';
|
||||||
|
import {MatButton} from '@angular/material/button';
|
||||||
|
import {MatFormField, MatInput, MatLabel} from '@angular/material/input';
|
||||||
|
import {NgIf} from '@angular/common';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-add-tutorial',
|
selector: 'app-add-tutorial',
|
||||||
templateUrl: './add-tutorial.component.html',
|
templateUrl: './add-tutorial.component.html',
|
||||||
styleUrls: ['./add-tutorial.component.scss'],
|
styleUrls: ['./add-tutorial.component.scss'],
|
||||||
standalone: false
|
imports: [
|
||||||
|
MatCardActions,
|
||||||
|
FormsModule,
|
||||||
|
MatCard,
|
||||||
|
MatCardHeader,
|
||||||
|
MatCardContent,
|
||||||
|
MatFormField,
|
||||||
|
MatLabel,
|
||||||
|
|
||||||
|
MatButton,
|
||||||
|
MatInput,
|
||||||
|
NgIf,
|
||||||
|
MatLabel,
|
||||||
|
|
||||||
|
],
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||||
})
|
})
|
||||||
export class AddTutorialComponent implements OnInit {
|
export class AddTutorialComponent implements OnInit {
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,23 @@
|
|||||||
import {Component, computed, model, OnInit} from '@angular/core';
|
import {Component, computed, CUSTOM_ELEMENTS_SCHEMA, model, OnInit} from '@angular/core';
|
||||||
|
|
||||||
import {User} from "../../models/user.model";
|
import {User} from "../../models/user.model";
|
||||||
import {MatChipInputEvent} from "@angular/material/chips";
|
import {MatChipGrid, MatChipInput, MatChipInputEvent, MatChipRow} from "@angular/material/chips";
|
||||||
import {MatAutocompleteSelectedEvent} from "@angular/material/autocomplete";
|
import {
|
||||||
|
MatAutocomplete,
|
||||||
|
MatAutocompleteSelectedEvent,
|
||||||
|
MatAutocompleteTrigger,
|
||||||
|
MatOption
|
||||||
|
} from "@angular/material/autocomplete";
|
||||||
import {COMMA, ENTER} from "@angular/cdk/keycodes";
|
import {COMMA, ENTER} from "@angular/cdk/keycodes";
|
||||||
import {AsyncPipe} from "@angular/common";
|
import {AsyncPipe, NgForOf} from "@angular/common";
|
||||||
import {FormControl} from "@angular/forms";
|
import {FormControl, ReactiveFormsModule} from "@angular/forms";
|
||||||
import {Observable, startWith} from "rxjs";
|
import {Observable, startWith} from "rxjs";
|
||||||
import {map} from "rxjs/operators";
|
import {map} from "rxjs/operators";
|
||||||
import {UserService} from '../../services/user.service';
|
import {UserService} from '../../services/user.service';
|
||||||
import {RolesService} from '../../services/roles.service';
|
import {RolesService} from '../../services/roles.service';
|
||||||
import {Role} from '../../models/role';
|
import {Role} from '../../models/role';
|
||||||
|
import {MatIcon} from '@angular/material/icon';
|
||||||
|
import {MatFormField} from '@angular/material/form-field';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -18,8 +25,21 @@ import {Role} from '../../models/role';
|
|||||||
selector: 'app-board-admin',
|
selector: 'app-board-admin',
|
||||||
templateUrl: './board-admin.component.html',
|
templateUrl: './board-admin.component.html',
|
||||||
styleUrls: ['./board-admin.component.scss'],
|
styleUrls: ['./board-admin.component.scss'],
|
||||||
standalone: false,
|
|
||||||
|
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
|
imports: [
|
||||||
|
MatAutocomplete,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
MatOption,
|
||||||
|
NgForOf,
|
||||||
|
MatFormField,
|
||||||
|
MatChipGrid,
|
||||||
|
|
||||||
|
MatChipRow,
|
||||||
|
MatIcon,
|
||||||
|
MatChipInput,
|
||||||
|
MatAutocompleteTrigger
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class BoardAdminComponent implements OnInit {
|
export class BoardAdminComponent implements OnInit {
|
||||||
private gridApi: any;
|
private gridApi: any;
|
||||||
|
|||||||
@@ -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,16 @@
|
|||||||
|
<div class="card" [ngClass]="cardClass()">
|
||||||
|
@if (showHeader()) {
|
||||||
|
<div class="card-header d-flex align-items-center justify-content-between" [ngClass]="headerClass()">
|
||||||
|
<div>
|
||||||
|
<h5>{{ cardTitle() }}</h5>
|
||||||
|
<ng-container *ngTemplateOutlet="headerTitleTemplate"></ng-container>
|
||||||
|
</div>
|
||||||
|
<ng-container *ngTemplateOutlet="headerOptionsTemplate"></ng-container>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (showContent()) {
|
||||||
|
<div class="card-body" [ngClass]="blockClass()" [style.padding.px]="padding()">
|
||||||
|
<ng-content></ng-content>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// Angular import
|
||||||
|
import { Component, ContentChild, ElementRef, TemplateRef, input } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-card',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule],
|
||||||
|
templateUrl: './card.component.html',
|
||||||
|
styleUrls: ['./card.component.scss']
|
||||||
|
})
|
||||||
|
export class CardComponent {
|
||||||
|
// public props
|
||||||
|
/**
|
||||||
|
* Title of card. It will be visible at left side of card header
|
||||||
|
*/
|
||||||
|
cardTitle = input<string>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to be applied at card level
|
||||||
|
*/
|
||||||
|
cardClass = input<string>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To hide content from card
|
||||||
|
*/
|
||||||
|
showContent = input(true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to be applied at card content.
|
||||||
|
*/
|
||||||
|
blockClass = input<string>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to be applied on card header
|
||||||
|
*/
|
||||||
|
headerClass = input<string>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To hide header from card
|
||||||
|
*/
|
||||||
|
showHeader = input(true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* padding around card content. default in px
|
||||||
|
*/
|
||||||
|
padding = input(20); // set default to 24 px
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template reference of header actions on custom header
|
||||||
|
*/
|
||||||
|
@ContentChild('headerOptionsTemplate') headerOptionsTemplate!: TemplateRef<ElementRef>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template reference of header actions besides title at left
|
||||||
|
*/
|
||||||
|
@ContentChild('headerTitleTemplate') headerTitleTemplate!: TemplateRef<ElementRef>;
|
||||||
|
}
|
||||||
@@ -14,7 +14,8 @@ import {MatFormField, MatLabel, MatSuffix} from "@angular/material/form-field";
|
|||||||
import {MatInput} from "@angular/material/input";
|
import {MatInput} from "@angular/material/input";
|
||||||
import {FormsModule} from "@angular/forms";
|
import {FormsModule} from "@angular/forms";
|
||||||
import {MatIcon} from "@angular/material/icon";
|
import {MatIcon} from "@angular/material/icon";
|
||||||
import {DialogData} from "../../app.component";
|
import {DialogData} from '../../main-module/main.component/main.component';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
|
<p>home.component works!</p>
|
||||||
+1
-3
@@ -8,12 +8,10 @@ describe('HomeComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ HomeComponent ]
|
imports: [HomeComponent]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(HomeComponent);
|
fixture = TestBed.createComponent(HomeComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-home.component',
|
||||||
|
imports: [],
|
||||||
|
templateUrl: './home.component.html',
|
||||||
|
styleUrl: './home.component.scss'
|
||||||
|
})
|
||||||
|
export class HomeComponent {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
<p-splitter [style]="{ height: '300px' }" styleClass="mb-8" layout="vertical">
|
|
||||||
<ng-template #panel>
|
|
||||||
<div class="flex items-center justify-center h-full">Panel 1</div>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template #panel>
|
|
||||||
<div class="flex items-center justify-center h-full">Panel 2</div>
|
|
||||||
<p-scrollPanel [style]="{ width: '100%', height: '150px' }">
|
|
||||||
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Lorem ipsum dolor sit amet...
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium...
|
|
||||||
</p>
|
|
||||||
<p class="m-0">
|
|
||||||
At vero eos et accusamus et iusto odio dignissimos...
|
|
||||||
dfsd
|
|
||||||
f
|
|
||||||
sdf
|
|
||||||
|
|
||||||
dsf
|
|
||||||
sd
|
|
||||||
f
|
|
||||||
sd
|
|
||||||
fs
|
|
||||||
fs
|
|
||||||
fsfs
|
|
||||||
fs
|
|
||||||
fs
|
|
||||||
fs
|
|
||||||
fs
|
|
||||||
fs
|
|
||||||
</p>
|
|
||||||
<app-article-comments />
|
|
||||||
</p-scrollPanel>
|
|
||||||
|
|
||||||
|
|
||||||
</ng-template>
|
|
||||||
</p-splitter>
|
|
||||||
|
|
||||||
<p-scrollPanel [style]="{ width: '100%', height: '150px' }">
|
|
||||||
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Lorem ipsum dolor sit amet...
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium...
|
|
||||||
</p>
|
|
||||||
<p class="m-0">
|
|
||||||
At vero eos et accusamus et iusto odio dignissimos...
|
|
||||||
dfsd
|
|
||||||
f
|
|
||||||
sdf
|
|
||||||
|
|
||||||
dsf
|
|
||||||
sd
|
|
||||||
f
|
|
||||||
sd
|
|
||||||
fs
|
|
||||||
fs
|
|
||||||
fsfs
|
|
||||||
fs
|
|
||||||
fs
|
|
||||||
fs
|
|
||||||
fs
|
|
||||||
fs
|
|
||||||
</p>
|
|
||||||
<app-article-comments />
|
|
||||||
</p-scrollPanel>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--
|
|
||||||
@defer (on viewport(container); prefetch on idle) {
|
|
||||||
<app-article-comments></app-article-comments>
|
|
||||||
} @loading {
|
|
||||||
<mat-progress-spinner></mat-progress-spinner>
|
|
||||||
|
|
||||||
loading
|
|
||||||
} @placeholder {
|
|
||||||
<div class="skeleton-loader"></div>
|
|
||||||
|
|
||||||
<app-article-comments></app-article-comments>
|
|
||||||
placeholder
|
|
||||||
} @error {
|
|
||||||
Error
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
<div #container>
|
|
||||||
<h1>How I feel about Angular</h1>
|
|
||||||
<article>
|
|
||||||
<p>
|
|
||||||
Angular is my favorite framework, and
|
|
||||||
this is why. Angular has the coolest
|
|
||||||
deferrable view feature that makes defer
|
|
||||||
loading content the easiest and most
|
|
||||||
ergonomic it could possibly be.
|
|
||||||
</p>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
@defer {
|
|
||||||
<app-article-comments />
|
|
||||||
} @placeholder (minimum 1s) {
|
|
||||||
<p>Placeholder for comments</p>
|
|
||||||
} @loading (minimum 1s; after 500ms) {
|
|
||||||
<p>Loading comments...</p>
|
|
||||||
} @error {
|
|
||||||
<p>Failed to load comments</p>
|
|
||||||
}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ng-container [ngComponentOutlet]="profileComponent()" />
|
|
||||||
-->
|
|
||||||
|
|
||||||
<mat-card #showComments appearance="outlined" >
|
|
||||||
<mat-card-header>
|
|
||||||
<mat-card-title>Tutorials</mat-card-title>
|
|
||||||
</mat-card-header>
|
|
||||||
<mat-card-content>
|
|
||||||
|
|
||||||
|
|
||||||
</mat-card-content>
|
|
||||||
</mat-card>
|
|
||||||
|
|
||||||
@defer (on hover; on interaction(showComments)) {
|
|
||||||
<app-article-comments />
|
|
||||||
} @placeholder ( ;minimum 1s) {
|
|
||||||
<p>Placeholder for comments</p>
|
|
||||||
} @loading (minimum 1s; after 500ms) {
|
|
||||||
<p>Loading comments...</p>
|
|
||||||
} @error {
|
|
||||||
<p>Failed to load comments</p>
|
|
||||||
}
|
|
||||||
|
|
||||||
@for (tutorial of tutorials; track $index){
|
|
||||||
<mat-card appearance="outlined" class="tutorial-card">
|
|
||||||
<mat-card-content [innerHTML]="tutorial.description">
|
|
||||||
</mat-card-content>
|
|
||||||
</mat-card>
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
mat-card{
|
|
||||||
margin: 20px;
|
|
||||||
background-color: rgba(0, 0, 0, 0.7);
|
|
||||||
}
|
|
||||||
mat-card-title{
|
|
||||||
color: cyan;
|
|
||||||
}
|
|
||||||
.tutorial-card{
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
import {Component, computed, OnInit} from '@angular/core';
|
|
||||||
import {TutorialService} from '../../services/tutorial.service';
|
|
||||||
|
|
||||||
import {Tutorial} from '../../models/tutorial.model';
|
|
||||||
import {ArticleComments} from '../article-comments/article-comments';
|
|
||||||
import {AddTutorialComponent} from '../add-tutorial/add-tutorial.component';
|
|
||||||
import { ScrollPanelModule } from 'primeng/scrollpanel';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-home',
|
|
||||||
templateUrl: './home.component.html',
|
|
||||||
styleUrls: ['./home.component.scss'],
|
|
||||||
standalone: false
|
|
||||||
})
|
|
||||||
export class HomeComponent implements OnInit {
|
|
||||||
content?: string;
|
|
||||||
|
|
||||||
tutorials?: Tutorial[];
|
|
||||||
|
|
||||||
constructor(private tutorialService: TutorialService) { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.retrieveTutorials();
|
|
||||||
}
|
|
||||||
retrieveTutorials(): void {
|
|
||||||
this.tutorialService.getAll()
|
|
||||||
.subscribe(
|
|
||||||
data => {
|
|
||||||
this.tutorials = data;
|
|
||||||
console.log(data);
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
profileComponent = computed(() => AddTutorialComponent);
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,16 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import {TokenStorageService} from '../../services/token-storage.service';
|
import {TokenStorageService} from '../../services/token-storage.service';
|
||||||
|
import {NgForOf, NgIf} from '@angular/common';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-profile',
|
selector: 'app-profile',
|
||||||
templateUrl: './profile.component.html',
|
templateUrl: './profile.component.html',
|
||||||
styleUrls: ['./profile.component.scss'],
|
imports: [
|
||||||
standalone: false
|
NgForOf,
|
||||||
|
NgIf
|
||||||
|
],
|
||||||
|
styleUrls: ['./profile.component.scss']
|
||||||
})
|
})
|
||||||
export class ProfileComponent implements OnInit {
|
export class ProfileComponent implements OnInit {
|
||||||
currentUser: any;
|
currentUser: any;
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import {AuthService} from '../../services/auth.service';
|
import {AuthService} from '../../services/auth.service';
|
||||||
|
import {FormsModule} from '@angular/forms';
|
||||||
|
import {NgIf} from '@angular/common';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-register',
|
selector: 'app-register',
|
||||||
templateUrl: './register.component.html',
|
templateUrl: './register.component.html',
|
||||||
styleUrls: ['./register.component.scss'],
|
imports: [
|
||||||
standalone: false
|
FormsModule,
|
||||||
|
NgIf
|
||||||
|
],
|
||||||
|
styleUrls: ['./register.component.scss']
|
||||||
})
|
})
|
||||||
export class RegisterComponent implements OnInit {
|
export class RegisterComponent implements OnInit {
|
||||||
form: any = {
|
form: any = {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,13 +3,18 @@ import { Component, OnInit } from '@angular/core';
|
|||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import {Tutorial} from '../../models/tutorial.model';
|
import {Tutorial} from '../../models/tutorial.model';
|
||||||
import {TutorialService} from '../../services/tutorial.service';
|
import {TutorialService} from '../../services/tutorial.service';
|
||||||
|
import {FormsModule} from '@angular/forms';
|
||||||
|
import {NgIf} from '@angular/common';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-tutorial-details',
|
selector: 'app-tutorial-details',
|
||||||
templateUrl: './tutorial-details.component.html',
|
templateUrl: './tutorial-details.component.html',
|
||||||
styleUrls: ['./tutorial-details.component.scss'],
|
imports: [
|
||||||
standalone: false
|
FormsModule,
|
||||||
|
NgIf
|
||||||
|
],
|
||||||
|
styleUrls: ['./tutorial-details.component.scss']
|
||||||
})
|
})
|
||||||
export class TutorialDetailsComponent implements OnInit {
|
export class TutorialDetailsComponent implements OnInit {
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,19 @@ import { Component, OnInit } from '@angular/core';
|
|||||||
|
|
||||||
import {Tutorial} from '../../models/tutorial.model';
|
import {Tutorial} from '../../models/tutorial.model';
|
||||||
import {TutorialService} from '../../services/tutorial.service';
|
import {TutorialService} from '../../services/tutorial.service';
|
||||||
|
import {FormsModule} from '@angular/forms';
|
||||||
|
import {RouterLink} from '@angular/router';
|
||||||
|
import {NgIf} from '@angular/common';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-tutorials-list',
|
selector: 'app-tutorials-list',
|
||||||
templateUrl: './tutorials-list.component.html',
|
templateUrl: './tutorials-list.component.html',
|
||||||
styleUrls: ['./tutorials-list.component.scss'],
|
imports: [
|
||||||
standalone: false
|
FormsModule,
|
||||||
|
RouterLink,
|
||||||
|
NgIf
|
||||||
|
],
|
||||||
|
styleUrls: ['./tutorials-list.component.scss']
|
||||||
})
|
})
|
||||||
export class TutorialsListComponent implements OnInit {
|
export class TutorialsListComponent implements OnInit {
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
@for (tutorial of tutorials; track $index){
|
||||||
|
<mat-card appearance="outlined" class="tutorial-card">
|
||||||
|
<mat-card-header>
|
||||||
|
<mat-card-title>{{tutorial.title}}</mat-card-title>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content [innerHTML]="tutorial.description">
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { TutorialsComponent } from './tutorials.component';
|
||||||
|
|
||||||
|
describe('TutorialsComponent', () => {
|
||||||
|
let component: TutorialsComponent;
|
||||||
|
let fixture: ComponentFixture<TutorialsComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [TutorialsComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(TutorialsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
||||||
|
import {Tutorial} from '../../models/tutorial.model';
|
||||||
|
import {TutorialService} from '../../services/tutorial.service';
|
||||||
|
import {MatCard, MatCardContent, MatCardHeader} from '@angular/material/card';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-tutorials.component',
|
||||||
|
imports: [
|
||||||
|
MatCard,
|
||||||
|
MatCardContent,
|
||||||
|
MatCardHeader
|
||||||
|
],
|
||||||
|
templateUrl: './tutorials.component.html',
|
||||||
|
styleUrl: './tutorials.component.scss',
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||||
|
})
|
||||||
|
export class TutorialsComponent {
|
||||||
|
tutorials?: Tutorial[];
|
||||||
|
|
||||||
|
constructor(private tutorialService: TutorialService) {
|
||||||
|
this.retrieveTutorials();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ngOnInit(): void {
|
||||||
|
// this.retrieveTutorials();
|
||||||
|
// }
|
||||||
|
|
||||||
|
retrieveTutorials(): void {
|
||||||
|
this.tutorialService.getAll()
|
||||||
|
.subscribe(
|
||||||
|
data => {
|
||||||
|
this.tutorials = data;
|
||||||
|
console.log(data);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<app-navigation
|
||||||
|
class="pc-sidebar"
|
||||||
|
[ngClass]="{
|
||||||
|
'navbar-collapsed': navCollapsed,
|
||||||
|
'mob-open': navCollapsedMob
|
||||||
|
}"
|
||||||
|
(NavCollapse)="this.navCollapsed = !this.navCollapsed"
|
||||||
|
/>
|
||||||
|
<app-nav-bar (NavCollapsedMob)="navMobClick()" (NavCollapse)="this.navCollapsed = !this.navCollapsed" />
|
||||||
|
<!--<app-nav-bar>
|
||||||
|
|
||||||
|
</app-nav-bar>-->
|
||||||
|
<!--<app-navigation></app-navigation>-->
|
||||||
|
<div class="pc-container">
|
||||||
|
<div class="coded-wrapper">
|
||||||
|
<div class="coded-content">
|
||||||
|
<div class="coded-inner-content">
|
||||||
|
<app-breadcrumb />
|
||||||
|
<div class="main-body">
|
||||||
|
<div class="page-wrapper">
|
||||||
|
<router-outlet />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pc-menu-overlay" (click)="closeMenu()" (keydown)="handleKeyDown($event)" tabindex="0"></div>
|
||||||
|
</div>
|
||||||
|
<footer class="pc-footer">
|
||||||
|
<div class="footer-wrapper container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col my-1">
|
||||||
|
<p class="m-0">
|
||||||
|
Copyright ©
|
||||||
|
<a href="https://codedthemes.com" target="_blank">CodedThemes</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto my-1">
|
||||||
|
<ul class="list-inline footer-link mb-0">
|
||||||
|
<li class="list-inline-item"><a href="https://codedthemes.com/" target="_blank">Home</a></li>
|
||||||
|
<li class="list-inline-item">
|
||||||
|
<a href="https://codedthemes.com/privacy-policy/" target="_blank">Privacy Policy</a>
|
||||||
|
</li>
|
||||||
|
<li class="list-inline-item"><a href="https://codedthemes.support-hub.io/" target="_blank">Contact us</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<app-configuration />
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// Angular import
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
// Project import
|
||||||
|
|
||||||
|
import { NavBarComponent } from './nav-bar/nav-bar.component';
|
||||||
|
import { NavigationComponent } from './navigation/navigation.component';
|
||||||
|
import { ConfigurationComponent } from './configuration/configuration.component';
|
||||||
|
import {BreadcrumbComponent} from '../../components/breadcrumb/breadcrumb.component';
|
||||||
|
//import { BreadcrumbComponent } from 'src/app/theme/shared/components/breadcrumb/breadcrumb.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-admin',
|
||||||
|
imports: [CommonModule, BreadcrumbComponent, NavigationComponent, NavBarComponent, RouterModule, ConfigurationComponent, NavigationComponent],
|
||||||
|
templateUrl: './admin-layout.component.html',
|
||||||
|
styleUrls: ['./admin-layout.component.scss']
|
||||||
|
})
|
||||||
|
export class AdminComponent {
|
||||||
|
// public props
|
||||||
|
navCollapsed: boolean = true;
|
||||||
|
navCollapsedMob: boolean = true;
|
||||||
|
|
||||||
|
// public method
|
||||||
|
navMobClick() {
|
||||||
|
if (this.navCollapsedMob && !document.querySelector('app-navigation.pc-sidebar')?.classList.contains('mob-open')) {
|
||||||
|
this.navCollapsedMob = !this.navCollapsedMob;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.navCollapsedMob = !this.navCollapsedMob;
|
||||||
|
}, 100);
|
||||||
|
} else {
|
||||||
|
this.navCollapsedMob = !this.navCollapsedMob;
|
||||||
|
}
|
||||||
|
if (document.querySelector('app-navigation.pc-sidebar')?.classList.contains('navbar-collapsed')) {
|
||||||
|
document.querySelector('app-navigation.pc-sidebar')?.classList.remove('navbar-collapsed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyDown(event: KeyboardEvent): void {
|
||||||
|
if (event.key === 'Escape') {
|
||||||
|
this.closeMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closeMenu() {
|
||||||
|
if (document.querySelector('app-navigation.pc-sidebar')?.classList.contains('mob-open')) {
|
||||||
|
document.querySelector('app-navigation.pc-sidebar')?.classList.remove('mob-open');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-configuration',
|
||||||
|
imports: [],
|
||||||
|
templateUrl: './configuration.component.html',
|
||||||
|
styleUrl: './configuration.component.scss'
|
||||||
|
})
|
||||||
|
export class ConfigurationComponent {}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<header class="pc-header">
|
||||||
|
<div class="header-wrapper">
|
||||||
|
<div class="pc-mob-drp">
|
||||||
|
<app-nav-left [navCollapsed]="navCollapsed" (NavCollapse)="navCollapse()" (NavCollapsedMob)="navCollapseMob()"></app-nav-left>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<app-nav-right />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.pc-header{
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
// angular import
|
||||||
|
import {Component, inject, OnInit, output} from '@angular/core';
|
||||||
|
|
||||||
|
// project import
|
||||||
|
|
||||||
|
import { NavLeftComponent } from './nav-left/nav-left.component';
|
||||||
|
import { NavRightComponent } from './nav-right/nav-right.component';
|
||||||
|
import {DOCUMENT} from '@angular/common';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-nav-bar',
|
||||||
|
imports: [NavLeftComponent, NavRightComponent],
|
||||||
|
templateUrl: './nav-bar.component.html',
|
||||||
|
styleUrls: ['./nav-bar.component.scss']
|
||||||
|
})
|
||||||
|
export class NavBarComponent implements OnInit{
|
||||||
|
private document = inject<Document>(DOCUMENT);
|
||||||
|
// public props
|
||||||
|
NavCollapse = output();
|
||||||
|
NavCollapsedMob = output();
|
||||||
|
|
||||||
|
navCollapsed: boolean = false;
|
||||||
|
windowWidth: number | undefined = 1000;
|
||||||
|
navCollapsedMob: boolean;
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
constructor() {
|
||||||
|
|
||||||
|
this.navCollapsedMob = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.windowWidth = this.document.defaultView?.innerWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public method
|
||||||
|
navCollapse() {
|
||||||
|
if (!!this.windowWidth && this.windowWidth >= 1025) {
|
||||||
|
this.navCollapsed = !this.navCollapsed;
|
||||||
|
this.NavCollapse.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
navCollapseMob() {
|
||||||
|
if (!!this.windowWidth && this.windowWidth < 1025) {
|
||||||
|
this.NavCollapsedMob.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<ul class="list-unstyled">
|
||||||
|
<li class="pc-h-item pc-sidebar-collapse">
|
||||||
|
<a
|
||||||
|
href="javascript:"
|
||||||
|
title="click to menu collapse"
|
||||||
|
class="pc-head-link ms-0"
|
||||||
|
[ngClass]="{ on: navCollapsed() }"
|
||||||
|
id="sidebar-hide mobile-collapse"
|
||||||
|
(click)="navCollapse()"
|
||||||
|
>
|
||||||
|
@if (navCollapsed()) {
|
||||||
|
|
||||||
|
<i antIcon type="menu-unfold" theme="outline"></i>
|
||||||
|
} @else {
|
||||||
|
<i antIcon type="menu-fold" theme="outline"></i>
|
||||||
|
}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="pc-h-item pc-sidebar-popup">
|
||||||
|
<a href="javascript:" class="pc-head-link ms-0" id="mobile-collapse1" (click)="this.NavCollapsedMob.emit()">
|
||||||
|
<i antIcon type="menu-fold" theme="outline"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="dropdown pc-h-item d-inline-flex d-md-none" ngbDropdown>
|
||||||
|
<a href="javascript:" class="pc-head-link dropdown-toggle arrow-none m-0" ngbDropdownToggle>
|
||||||
|
<i class="ti ti-search"></i>
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-menu dropdowm-menu-end pc-h-dropdown drp-search" ngbDropdownMenu>
|
||||||
|
<form class="px-3">
|
||||||
|
<div class="form-group mb-0 d-flex align-items-center">
|
||||||
|
<i class="search f-12" antIcon type="search" theme="outline"></i>
|
||||||
|
<input type="search" class="form-control border-0 shadow-none" placeholder="Ctrl + K" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="pc-h-item d-none d-md-inline-flex">
|
||||||
|
<form class="header-search">
|
||||||
|
<i class="search f-12" antIcon type="search" theme="outline"></i>
|
||||||
|
<input type="search" class="form-control" placeholder="Ctrl + K" />
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// Angular import
|
||||||
|
import {CommonModule, DOCUMENT} from '@angular/common';
|
||||||
|
import { Component, inject, input, output } from '@angular/core';
|
||||||
|
|
||||||
|
// project import
|
||||||
|
|
||||||
|
// icons
|
||||||
|
import { IconService, IconDirective } from '@ant-design/icons-angular';
|
||||||
|
import { MenuUnfoldOutline, MenuFoldOutline, SearchOutline } from '@ant-design/icons-angular/icons';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-nav-left',
|
||||||
|
imports: [IconDirective, CommonModule],
|
||||||
|
templateUrl: './nav-left.component.html',
|
||||||
|
styleUrls: ['./nav-left.component.scss']
|
||||||
|
})
|
||||||
|
export class NavLeftComponent {
|
||||||
|
private iconService = inject(IconService);
|
||||||
|
private document = inject(DOCUMENT);
|
||||||
|
|
||||||
|
// public props
|
||||||
|
navCollapsed = input.required<boolean>();
|
||||||
|
NavCollapse = output();
|
||||||
|
NavCollapsedMob = output();
|
||||||
|
windowWidth: number | undefined = 1000;
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
constructor() {
|
||||||
|
this.windowWidth = this.document.defaultView?.innerWidth;
|
||||||
|
this.iconService.addIcon(...[MenuUnfoldOutline, MenuFoldOutline, SearchOutline]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// public method
|
||||||
|
navCollapse() {
|
||||||
|
this.NavCollapse.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
<ul class="list-unstyled">
|
||||||
|
<li class="pc-h-item">
|
||||||
|
<a href="https://github.com/codedthemes/mantis-free-angular-admin-template" target="_blank" class="pc-head-link me-0 bg-gray-200">
|
||||||
|
<i antIcon type="github" theme="outline"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="dropdown pc-h-item" ngbDropdown>
|
||||||
|
<a href="javascript:" class="pc-head-link dropdown-toggle arrow-none me-0 bg-gray-200" data-bs-toggle="dropdown" ngbDropdownToggle>
|
||||||
|
<i antIcon type="bell" theme="outline"></i>
|
||||||
|
<span class="badge bg-primary pc-h-badge">3</span>
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-menu dropdown-notification dropdown-menu-end pc-h-dropdown" ngbDropdownMenu>
|
||||||
|
<div class="dropdown-header d-flex align-items-center justify-content-between">
|
||||||
|
<h5 class="m-0">Notification</h5>
|
||||||
|
<a class="bg-transparent"><i class="text-success d-flex f-20" antIcon theme="outline" type="check-circle"></i></a>
|
||||||
|
</div>
|
||||||
|
<div class="dropdown-divider mb-0"></div>
|
||||||
|
<ng-scrollbar style="min-height: 280px" visibility="hover">
|
||||||
|
<div class="dropdown-header p-0 text-wrap header-notification-scroll">
|
||||||
|
<div class="list-group list-group-flush w-100">
|
||||||
|
<a class="list-group-item list-group-item-action">
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
<div class="user-avatar bg-light-success"><i class="d-flex" antIcon theme="outline" type="gift"></i></div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grow-1 ms-3">
|
||||||
|
<span class="float-end text-muted">3:00 AM</span>
|
||||||
|
<p class="text-body mb-0">
|
||||||
|
It's
|
||||||
|
<b>Cristina danny's</b>
|
||||||
|
birthday today.
|
||||||
|
</p>
|
||||||
|
<span class="text-muted">2 min ago</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="list-group-item list-group-item-action">
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
<div class="user-avatar bg-light-primary"><i class="d-flex" antIcon theme="outline" type="message"></i></div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grow-1 ms-3">
|
||||||
|
<span class="float-end text-muted">6:00 PM</span>
|
||||||
|
<p class="text-body mb-1">
|
||||||
|
<b>Aida Burg</b>
|
||||||
|
commented your post.
|
||||||
|
</p>
|
||||||
|
<span class="text-muted">5 August</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="list-group-item list-group-item-action">
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
<div class="user-avatar bg-light-danger"><i class="d-flex" antIcon theme="outline" type="setting"></i></div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grow-1 ms-3">
|
||||||
|
<span class="float-end text-muted">2:45 PM</span>
|
||||||
|
<p class="text-body mb-1">
|
||||||
|
Your Profile is Complete
|
||||||
|
<b>60%</b>
|
||||||
|
</p>
|
||||||
|
<span class="text-muted">7 hours ago</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="list-group-item list-group-item-action">
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
<div class="user-avatar bg-light-primary"><i class="d-flex" antIcon theme="outline" type="phone"></i></div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grow-1 ms-3">
|
||||||
|
<span class="float-end text-muted">9:10 PM</span>
|
||||||
|
<p class="text-body mb-1">
|
||||||
|
<b>Cristina Danny</b>
|
||||||
|
invited to join
|
||||||
|
<b>Meeting.</b>
|
||||||
|
</p>
|
||||||
|
<span class="text-muted">Daily scrum meeting time</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-scrollbar>
|
||||||
|
<div class="dropdown-divider mt-0"></div>
|
||||||
|
<div class="text-center py-2">
|
||||||
|
<a href="javascript:" class="link-primary">View all</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="dropdown pc-h-item header-user-profile" ngbDropdown>
|
||||||
|
<a href="javascript:" class="pc-head-link dropdown-toggle arrow-none me-0" ngbDropdownToggle>
|
||||||
|
<img src="assets/images/user/avatar-2.jpg" alt="user-image" class="user-avatar me-2" />
|
||||||
|
<span class="f-w-600">John Doe</span>
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-menu dropdown-user-profile dropdown-menu-end pc-h-dropdown" ngbDropdownMenu>
|
||||||
|
<div class="dropdown-header">
|
||||||
|
<div class="d-flex mb-1">
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
<img src="assets/images/user/avatar-2.jpg" alt="user-image" class="user-avatar wid-35" />
|
||||||
|
</div>
|
||||||
|
<div class="flex-grow-1 ms-3 text-start">
|
||||||
|
<h6 class="mb-0">JWT User</h6>
|
||||||
|
<span>UI/UX Designer</span>
|
||||||
|
</div>
|
||||||
|
<a href="javascript:" class="bg-transparent"><i class="d-flex f-20" antIcon theme="outline" type="logout"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul ngbNav #nav="ngbNav" class="nav drp-tabs nav-fill nav-tabs">
|
||||||
|
<li ngbNavItem="1">
|
||||||
|
<a ngbNavLink>
|
||||||
|
<i antIcon theme="outline" type="user" class="me-2"></i>
|
||||||
|
Profile
|
||||||
|
</a>
|
||||||
|
<ng-template ngbNavContent>
|
||||||
|
@for (task of profile; track task) {
|
||||||
|
<div>
|
||||||
|
<a href="javascript:" class="dropdown-item">
|
||||||
|
<i class="text-muted" antIcon theme="outline" type="{{ task.icon }}"></i>
|
||||||
|
<span>{{ task.title }}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</ng-template>
|
||||||
|
</li>
|
||||||
|
<li ngbNavItem="2">
|
||||||
|
<a ngbNavLink>
|
||||||
|
<i class="me-2" antIcon theme="outline" type="setting"></i>
|
||||||
|
Setting
|
||||||
|
</a>
|
||||||
|
<ng-template ngbNavContent>
|
||||||
|
@for (task of setting; track task) {
|
||||||
|
<div>
|
||||||
|
<a href="javascript:" class="dropdown-item">
|
||||||
|
<i class="text-muted" antIcon theme="outline" type="{{ task.icon }}"></i>
|
||||||
|
<span>{{ task.title }}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</ng-template>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div [ngbNavOutlet]="nav"></div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
// angular import
|
||||||
|
import {Component, inject, input, OnInit, output} from '@angular/core';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
// project import
|
||||||
|
|
||||||
|
// icon
|
||||||
|
import { IconService, IconDirective } from '@ant-design/icons-angular';
|
||||||
|
import {
|
||||||
|
BellOutline,
|
||||||
|
SettingOutline,
|
||||||
|
GiftOutline,
|
||||||
|
MessageOutline,
|
||||||
|
PhoneOutline,
|
||||||
|
CheckCircleOutline,
|
||||||
|
LogoutOutline,
|
||||||
|
EditOutline,
|
||||||
|
UserOutline,
|
||||||
|
ProfileOutline,
|
||||||
|
WalletOutline,
|
||||||
|
QuestionCircleOutline,
|
||||||
|
LockOutline,
|
||||||
|
CommentOutline,
|
||||||
|
UnorderedListOutline,
|
||||||
|
ArrowRightOutline,
|
||||||
|
GithubOutline
|
||||||
|
} from '@ant-design/icons-angular/icons';
|
||||||
|
import { NgbDropdownModule, NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import { NgScrollbarModule } from 'ngx-scrollbar';
|
||||||
|
import {DOCUMENT} from '@angular/common';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-nav-right',
|
||||||
|
imports: [IconDirective, RouterModule, NgScrollbarModule, NgbNavModule, NgbDropdownModule],
|
||||||
|
templateUrl: './nav-right.component.html',
|
||||||
|
styleUrls: ['./nav-right.component.scss']
|
||||||
|
})
|
||||||
|
export class NavRightComponent implements OnInit{
|
||||||
|
private iconService = inject(IconService);
|
||||||
|
private document = inject(DOCUMENT);
|
||||||
|
//private window = inject(Window);
|
||||||
|
styleSelectorToggle = input<boolean>();
|
||||||
|
Customize = output();
|
||||||
|
windowWidth: number | undefined = 1000;
|
||||||
|
screenFull: boolean = true;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
|
||||||
|
this.iconService.addIcon(
|
||||||
|
...[
|
||||||
|
CheckCircleOutline,
|
||||||
|
GiftOutline,
|
||||||
|
MessageOutline,
|
||||||
|
SettingOutline,
|
||||||
|
PhoneOutline,
|
||||||
|
LogoutOutline,
|
||||||
|
UserOutline,
|
||||||
|
EditOutline,
|
||||||
|
ProfileOutline,
|
||||||
|
QuestionCircleOutline,
|
||||||
|
LockOutline,
|
||||||
|
CommentOutline,
|
||||||
|
UnorderedListOutline,
|
||||||
|
ArrowRightOutline,
|
||||||
|
BellOutline,
|
||||||
|
GithubOutline,
|
||||||
|
WalletOutline
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.windowWidth = this.document.defaultView?.innerWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
profile = [
|
||||||
|
{
|
||||||
|
icon: 'edit',
|
||||||
|
title: 'Edit Profile'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'user',
|
||||||
|
title: 'View Profile'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'profile',
|
||||||
|
title: 'Social Profile'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'wallet',
|
||||||
|
title: 'Billing'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'logout',
|
||||||
|
title: 'Logout'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
setting = [
|
||||||
|
{
|
||||||
|
icon: 'question-circle',
|
||||||
|
title: 'Support'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'user',
|
||||||
|
title: 'Account Settings'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'lock',
|
||||||
|
title: 'Privacy Center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'comment',
|
||||||
|
title: 'Feedback'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'unordered-list',
|
||||||
|
title: 'History'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
<li data-username="mantis dashboard" class="nav-item coded-hasmenu" [routerLinkActive]="['active']">
|
||||||
|
<a [routerLinkActive]="['active']" (click)="navCollapse($event)">
|
||||||
|
@if (item.icon) {
|
||||||
|
<span class="coded-micon">
|
||||||
|
<i antIcon type="{{ item.icon }}" theme="outline"></i>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
<span class="coded-mtext">
|
||||||
|
{{ item.title }}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<ul class="coded-submenu" [routerLinkActive]="['active']" [ngClass]="item.classes!">
|
||||||
|
@for (item of item.children; track item) {
|
||||||
|
@if (item.type === 'item') {
|
||||||
|
<app-nav-item [item]="item"></app-nav-item>
|
||||||
|
} @else if (item.type === 'collapse') {
|
||||||
|
<app-nav-collapse [item]="item"></app-nav-collapse>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
+88
@@ -0,0 +1,88 @@
|
|||||||
|
// Angular import
|
||||||
|
import {Component, inject, Input, OnInit, output} from '@angular/core';
|
||||||
|
import { animate, style, transition, trigger } from '@angular/animations';
|
||||||
|
import {CommonModule, DOCUMENT} from '@angular/common';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
// project import
|
||||||
|
import { NavigationItem } from '../../navigation';
|
||||||
|
|
||||||
|
import { NavItemComponent } from '../nav-item/nav-item.component';
|
||||||
|
import { IconDirective } from '@ant-design/icons-angular';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-nav-collapse',
|
||||||
|
imports: [CommonModule, IconDirective, RouterModule, NavItemComponent],
|
||||||
|
templateUrl: './nav-collapse.component.html',
|
||||||
|
styleUrls: ['./nav-collapse.component.scss'],
|
||||||
|
animations: [
|
||||||
|
trigger('slideInOut', [
|
||||||
|
transition(':enter', [
|
||||||
|
style({ transform: 'translateY(-100%)', display: 'block' }),
|
||||||
|
animate('250ms ease-in', style({ transform: 'translateY(0%)' }))
|
||||||
|
]),
|
||||||
|
transition(':leave', [animate('250ms ease-in', style({ transform: 'translateY(-100%)' }))])
|
||||||
|
])
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class NavCollapseComponent implements OnInit{
|
||||||
|
|
||||||
|
private document = inject(DOCUMENT);
|
||||||
|
|
||||||
|
// public props
|
||||||
|
|
||||||
|
// Compact Menu in use For Sub Child Open in sidebar menu
|
||||||
|
showCollapseItem = output();
|
||||||
|
|
||||||
|
// all Version Get Item(Component Name Take)
|
||||||
|
@Input() item!: NavigationItem;
|
||||||
|
|
||||||
|
windowWidth: number | undefined = 1000;
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
constructor() {
|
||||||
|
//this.windowWidth = window.innerWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.windowWidth = this.document.defaultView?.innerWidth;throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// public method
|
||||||
|
navCollapse(e: MouseEvent) {
|
||||||
|
let parent = e.target as HTMLElement;
|
||||||
|
|
||||||
|
if (parent?.tagName === 'SPAN') {
|
||||||
|
parent = parent.parentElement!;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = (parent as HTMLElement).parentElement as HTMLElement;
|
||||||
|
|
||||||
|
const sections = document.querySelectorAll('.coded-hasmenu');
|
||||||
|
for (let i = 0; i < sections.length; i++) {
|
||||||
|
if (sections[i] !== parent) {
|
||||||
|
sections[i].classList.remove('coded-trigger');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let first_parent = parent.parentElement;
|
||||||
|
let pre_parent = ((parent as HTMLElement).parentElement as HTMLElement).parentElement as HTMLElement;
|
||||||
|
if (first_parent?.classList.contains('coded-hasmenu')) {
|
||||||
|
do {
|
||||||
|
first_parent?.classList.add('coded-trigger');
|
||||||
|
first_parent = ((first_parent as HTMLElement).parentElement as HTMLElement).parentElement as HTMLElement;
|
||||||
|
} while (first_parent.classList.contains('coded-hasmenu'));
|
||||||
|
} else if (pre_parent.classList.contains('coded-submenu')) {
|
||||||
|
do {
|
||||||
|
pre_parent?.parentElement?.classList.add('coded-trigger');
|
||||||
|
pre_parent = (((pre_parent as HTMLElement).parentElement as HTMLElement).parentElement as HTMLElement).parentElement as HTMLElement;
|
||||||
|
} while (pre_parent.classList.contains('coded-submenu'));
|
||||||
|
}
|
||||||
|
parent.classList.toggle('coded-trigger');
|
||||||
|
}
|
||||||
|
|
||||||
|
// for Compact Menu
|
||||||
|
subMenuCollapse(item: void) {
|
||||||
|
this.showCollapseItem.emit(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
<!-- Vertical layout -->
|
||||||
|
<ng-scrollbar style="height: calc(100vh - 49px)" visibility="hover" id="nav-ps-mantis">
|
||||||
|
<div class="navbar-content">
|
||||||
|
<ul class="nav coded-inner-navbar" (clickOutside)="fireOutClick()" (mouseleave)="navMob()">
|
||||||
|
@for (item of navigations; track item) {
|
||||||
|
@if (item.type === 'group') {
|
||||||
|
<app-nav-group [item]="item"></app-nav-group>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
<div class="m-4 mb-0">
|
||||||
|
<div class="card nav-card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex flex-column align-items-center">
|
||||||
|
<img src="assets/images/avatar-group.png" alt="user" class="img-fluid" />
|
||||||
|
<div class="m-t-20 text-center">
|
||||||
|
<h5 class="mb-0">Mantis Pro</h5>
|
||||||
|
<span class="text-muted">Checkout pro features</span>
|
||||||
|
</div>
|
||||||
|
<div class="m-t-20 text-center">
|
||||||
|
<a
|
||||||
|
href="https://codedthemes.com/item/mantis-angular-admin-template/?utm_source=free_demo&utm_medium=codedthemes&utm_campaign=button_download_premium"
|
||||||
|
target="_blank"
|
||||||
|
class="btn btn-primary text-white"
|
||||||
|
>
|
||||||
|
Pro
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-scrollbar>
|
||||||
+106
@@ -0,0 +1,106 @@
|
|||||||
|
// Angular import
|
||||||
|
import { Component, OnInit, inject, output } from '@angular/core';
|
||||||
|
import {CommonModule, DOCUMENT, Location, LocationStrategy} from '@angular/common';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
// project import
|
||||||
|
import { NavigationItem, NavigationItems } from '../navigation';
|
||||||
|
//import { environment } from 'src/environments/environment';
|
||||||
|
|
||||||
|
import { NavGroupComponent } from './nav-group/nav-group.component';
|
||||||
|
|
||||||
|
// icon
|
||||||
|
import { IconService } from '@ant-design/icons-angular';
|
||||||
|
import {
|
||||||
|
DashboardOutline,
|
||||||
|
CreditCardOutline,
|
||||||
|
LoginOutline,
|
||||||
|
QuestionOutline,
|
||||||
|
ChromeOutline,
|
||||||
|
FontSizeOutline,
|
||||||
|
ProfileOutline,
|
||||||
|
BgColorsOutline,
|
||||||
|
AntDesignOutline
|
||||||
|
} from '@ant-design/icons-angular/icons';
|
||||||
|
import { NgScrollbarModule } from 'ngx-scrollbar';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-nav-content',
|
||||||
|
imports: [CommonModule, RouterModule, NavGroupComponent, NgScrollbarModule],
|
||||||
|
templateUrl: './nav-content.component.html',
|
||||||
|
styleUrls: ['./nav-content.component.scss']
|
||||||
|
})
|
||||||
|
export class NavContentComponent implements OnInit {
|
||||||
|
private location = inject(Location);
|
||||||
|
private locationStrategy = inject(LocationStrategy);
|
||||||
|
private iconService = inject(IconService)
|
||||||
|
private document = inject(DOCUMENT);
|
||||||
|
|
||||||
|
// public props
|
||||||
|
NavCollapsedMob = output();
|
||||||
|
|
||||||
|
navigations: NavigationItem[];
|
||||||
|
|
||||||
|
// version
|
||||||
|
title = 'Demo application for version numbering';
|
||||||
|
//currentApplicationVersion = environment.appVersion;
|
||||||
|
|
||||||
|
navigation = NavigationItems;
|
||||||
|
windowWidth: number | undefined = 1000;
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
constructor() {
|
||||||
|
this.iconService.addIcon(
|
||||||
|
...[
|
||||||
|
DashboardOutline,
|
||||||
|
CreditCardOutline,
|
||||||
|
FontSizeOutline,
|
||||||
|
LoginOutline,
|
||||||
|
ProfileOutline,
|
||||||
|
BgColorsOutline,
|
||||||
|
AntDesignOutline,
|
||||||
|
ChromeOutline,
|
||||||
|
QuestionOutline
|
||||||
|
]
|
||||||
|
);
|
||||||
|
this.navigations = NavigationItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Life cycle events
|
||||||
|
ngOnInit() {
|
||||||
|
if (!!this.windowWidth && this.windowWidth < 1025) {
|
||||||
|
(this.document.querySelector('.coded-navbar') as HTMLDivElement)?.classList.add('menupos-static');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fireOutClick() {
|
||||||
|
let current_url = this.location.path();
|
||||||
|
const baseHref = this.locationStrategy.getBaseHref();
|
||||||
|
if (baseHref) {
|
||||||
|
current_url = baseHref + this.location.path();
|
||||||
|
}
|
||||||
|
const link = "a.nav-link[ href='" + current_url + "' ]";
|
||||||
|
const ele = document?.querySelector(link);
|
||||||
|
if (ele !== null && ele !== undefined) {
|
||||||
|
const parent = ele.parentElement;
|
||||||
|
const up_parent = parent?.parentElement?.parentElement;
|
||||||
|
const last_parent = up_parent?.parentElement;
|
||||||
|
if (parent?.classList.contains('coded-hasmenu')) {
|
||||||
|
parent.classList.add('coded-trigger');
|
||||||
|
parent.classList.add('active');
|
||||||
|
} else if (up_parent?.classList.contains('coded-hasmenu')) {
|
||||||
|
up_parent.classList.add('coded-trigger');
|
||||||
|
up_parent.classList.add('active');
|
||||||
|
} else if (last_parent?.classList.contains('coded-hasmenu')) {
|
||||||
|
last_parent.classList.add('coded-trigger');
|
||||||
|
last_parent.classList.add('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
navMob() {
|
||||||
|
if (!!this.windowWidth && this.windowWidth < 1025 && document.querySelector('app-navigation.coded-navbar')?.classList.contains('mob-open')) {
|
||||||
|
this.NavCollapsedMob.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
<li class="nav-item coded-menu-caption">
|
||||||
|
<label>{{ item().title }}</label>
|
||||||
|
</li>
|
||||||
|
@for (item of item().children; track item) {
|
||||||
|
@if (item.type === 'collapse') {
|
||||||
|
<app-nav-collapse [item]="item"></app-nav-collapse>
|
||||||
|
} @else if (item.type === 'item') {
|
||||||
|
<app-nav-item [item]="item"></app-nav-item>
|
||||||
|
}
|
||||||
|
}
|
||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
// Angular import
|
||||||
|
import { Component, OnInit, inject, input } from '@angular/core';
|
||||||
|
import {CommonModule, DOCUMENT, Location} from '@angular/common';
|
||||||
|
|
||||||
|
// project import
|
||||||
|
import { NavigationItem } from '../../navigation';
|
||||||
|
|
||||||
|
import { NavCollapseComponent } from '../nav-collapse/nav-collapse.component';
|
||||||
|
import { NavItemComponent } from '../nav-item/nav-item.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-nav-group',
|
||||||
|
imports: [CommonModule, NavCollapseComponent, NavItemComponent],
|
||||||
|
templateUrl: './nav-group.component.html',
|
||||||
|
styleUrls: ['./nav-group.component.scss']
|
||||||
|
})
|
||||||
|
export class NavGroupComponent implements OnInit {
|
||||||
|
private location = inject(Location);
|
||||||
|
private document = inject(DOCUMENT);
|
||||||
|
// public props
|
||||||
|
|
||||||
|
// All Version in Group Name
|
||||||
|
item = input.required<NavigationItem>();
|
||||||
|
|
||||||
|
// Life cycle events
|
||||||
|
ngOnInit() {
|
||||||
|
// at reload time active and trigger link
|
||||||
|
let current_url: string | any = this.location.path();
|
||||||
|
// eslint-disable-next-line
|
||||||
|
// @ts-ignore
|
||||||
|
if (this.location['_baseHref']) {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
current_url = this.location['_baseHref'] + this.location.path();
|
||||||
|
}
|
||||||
|
|
||||||
|
const link = "a.nav-link[ href='" + current_url + "' ]";
|
||||||
|
//if(this.document === undefined) return;
|
||||||
|
const ele = this.document?.querySelector(link);
|
||||||
|
if (ele !== null && ele !== undefined) {
|
||||||
|
const parent = ele.parentElement;
|
||||||
|
const up_parent = parent?.parentElement?.parentElement;
|
||||||
|
const pre_parent = up_parent?.parentElement;
|
||||||
|
const last_parent = up_parent?.parentElement?.parentElement?.parentElement?.parentElement;
|
||||||
|
if (parent?.classList.contains('coded-hasmenu')) {
|
||||||
|
parent?.classList.add('coded-trigger');
|
||||||
|
parent?.classList.add('active');
|
||||||
|
} else if (up_parent?.classList.contains('coded-hasmenu')) {
|
||||||
|
up_parent?.classList.add('coded-trigger');
|
||||||
|
up_parent?.classList.add('active');
|
||||||
|
} else if (pre_parent?.classList.contains('coded-hasmenu')) {
|
||||||
|
pre_parent?.classList.add('coded-trigger');
|
||||||
|
pre_parent?.classList.add('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_parent?.classList.contains('coded-hasmenu')) {
|
||||||
|
last_parent?.classList.add('coded-trigger');
|
||||||
|
if (pre_parent?.classList.contains('coded-hasmenu')) {
|
||||||
|
pre_parent?.classList.add('coded-trigger');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_parent?.classList.add('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
@if (item.url && !item.external) {
|
||||||
|
<li [ngClass]="item.classes!" [routerLinkActive]="['active']">
|
||||||
|
<a [target]="item.target ? '_blank' : '_self'" [routerLink]="[item.url]" (click)="closeOtherMenu($event)">
|
||||||
|
@if (item.icon) {
|
||||||
|
<span class="coded-micon">
|
||||||
|
<i antIcon type="{{ item.icon }}" theme="outline"></i>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
@if (item.icon) {
|
||||||
|
<span class="coded-mtext">{{ item.title }}</span>
|
||||||
|
} @else {
|
||||||
|
{{ item.title }}
|
||||||
|
}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
@if (item.url && item.external) {
|
||||||
|
<li [ngClass]="item.classes!">
|
||||||
|
<a [target]="item.target ? '_blank' : '_self'" [href]="item.url">
|
||||||
|
@if (item.icon) {
|
||||||
|
<span class="coded-micon">
|
||||||
|
<i antIcon type="{{ item.icon }}" theme="outline"></i>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
@if (item.icon) {
|
||||||
|
<span class="coded-mtext">{{ item.title }}</span>
|
||||||
|
} @else {
|
||||||
|
{{ item.title }}
|
||||||
|
}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
// Angular import
|
||||||
|
import {Component, inject, Input} from '@angular/core';
|
||||||
|
import {CommonModule, DOCUMENT} from '@angular/common';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
// Project import
|
||||||
|
import { NavigationItem } from '../../navigation';
|
||||||
|
|
||||||
|
import { IconDirective } from '@ant-design/icons-angular';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-nav-item',
|
||||||
|
imports: [CommonModule, IconDirective, RouterModule],
|
||||||
|
templateUrl: './nav-item.component.html',
|
||||||
|
styleUrls: ['./nav-item.component.scss']
|
||||||
|
})
|
||||||
|
export class NavItemComponent {
|
||||||
|
private document = inject(DOCUMENT);
|
||||||
|
|
||||||
|
// public props
|
||||||
|
@Input() item!: NavigationItem;
|
||||||
|
|
||||||
|
// public method
|
||||||
|
closeOtherMenu(event: MouseEvent) {
|
||||||
|
const ele = event.target as HTMLElement;
|
||||||
|
if (ele !== null && ele !== undefined) {
|
||||||
|
const parent = ele.parentElement as HTMLElement;
|
||||||
|
const up_parent = ((parent.parentElement as HTMLElement).parentElement as HTMLElement).parentElement as HTMLElement;
|
||||||
|
const last_parent = up_parent.parentElement;
|
||||||
|
const sections = this.document.querySelectorAll('.coded-hasmenu');
|
||||||
|
for (let i = 0; i < sections.length; i++) {
|
||||||
|
sections[i].classList.remove('active');
|
||||||
|
sections[i].classList.remove('coded-trigger');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent.classList.contains('coded-hasmenu')) {
|
||||||
|
parent.classList.add('coded-trigger');
|
||||||
|
parent.classList.add('active');
|
||||||
|
} else if (up_parent.classList.contains('coded-hasmenu')) {
|
||||||
|
up_parent.classList.add('coded-trigger');
|
||||||
|
up_parent.classList.add('active');
|
||||||
|
} else if (last_parent?.classList.contains('coded-hasmenu')) {
|
||||||
|
last_parent.classList.add('coded-trigger');
|
||||||
|
last_parent.classList.add('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((document.querySelector('app-navigation.pc-sidebar') as HTMLDivElement).classList.contains('mob-open')) {
|
||||||
|
(document.querySelector('app-navigation.pc-sidebar') as HTMLDivElement).classList.remove('mob-open');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<nav>
|
||||||
|
<div class="navbar-wrapper">
|
||||||
|
<div class="m-header">
|
||||||
|
<a href="javascript:" class="b-brand">
|
||||||
|
<img src="assets/images/logo-dark.svg" alt="theme-logo" class="logo logo-dark logo-lg" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<app-nav-content (NavCollapsedMob)="navCollapseMob()" class="scroll-div w-100 compact"></app-nav-content>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
// Angular import
|
||||||
|
import {Component, EventEmitter, inject, OnInit, Output, output} from '@angular/core';
|
||||||
|
import {CommonModule, DOCUMENT} from '@angular/common';
|
||||||
|
import {NavContentComponent} from './nav-content/nav-content.component';
|
||||||
|
|
||||||
|
// project import
|
||||||
|
|
||||||
|
//import { NavContentComponent } from './nav-content/nav-content.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-navigation',
|
||||||
|
// imports: [ CommonModule],
|
||||||
|
templateUrl: './navigation.component.html',
|
||||||
|
imports: [
|
||||||
|
NavContentComponent
|
||||||
|
],
|
||||||
|
styleUrls: ['./navigation.component.scss']
|
||||||
|
})
|
||||||
|
export class NavigationComponent implements OnInit{
|
||||||
|
|
||||||
|
private document = inject<Document>(DOCUMENT);
|
||||||
|
|
||||||
|
// media 1025 After Use Menu Open
|
||||||
|
NavCollapsedMob = output();
|
||||||
|
|
||||||
|
navCollapsedMob:boolean;
|
||||||
|
windowWidth: number | undefined = 1000;
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
constructor() {
|
||||||
|
//window.
|
||||||
|
// this.windowWidth = !document ? 0 : !document.defaultView ? 0 : document.defaultView?.innerWidth;
|
||||||
|
//this.windowWidth = document.defaultView !== null? document.defaultView.innerWidth : 1000;//window.innerWidth;
|
||||||
|
this.navCollapsedMob = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.windowWidth = this.document.defaultView?.innerWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public method
|
||||||
|
// @Output() NavCollapse = new EventEmitter<unknown>();
|
||||||
|
@Output() NavCollapse = new EventEmitter<unknown>();
|
||||||
|
navCollapseMob() {
|
||||||
|
if (!!this.windowWidth && this.windowWidth < 1025) {
|
||||||
|
this.NavCollapsedMob.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
export interface NavigationItem {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
type: 'item' | 'collapse' | 'group';
|
||||||
|
translate?: string;
|
||||||
|
icon?: string;
|
||||||
|
hidden?: boolean;
|
||||||
|
url?: string;
|
||||||
|
classes?: string;
|
||||||
|
groupClasses?: string;
|
||||||
|
exactMatch?: boolean;
|
||||||
|
external?: boolean;
|
||||||
|
target?: boolean;
|
||||||
|
breadcrumbs?: boolean;
|
||||||
|
children?: NavigationItem[];
|
||||||
|
link?: string;
|
||||||
|
description?: string;
|
||||||
|
path?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const NavigationItems: NavigationItem[] = [
|
||||||
|
{
|
||||||
|
id: 'admin',
|
||||||
|
title: 'Admin',
|
||||||
|
type: 'group',
|
||||||
|
icon: 'icon-navigation',
|
||||||
|
url: '/main/admin/welcome',
|
||||||
|
target: true,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 'settings',
|
||||||
|
title: 'Settings',
|
||||||
|
type: 'item',
|
||||||
|
classes: 'nav-item',
|
||||||
|
url: '/main/admin/settings',
|
||||||
|
icon: 'dashboard',
|
||||||
|
// breadcrumbs: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'system',
|
||||||
|
title: 'System',
|
||||||
|
type: 'item',
|
||||||
|
classes: 'nav-item',
|
||||||
|
url: '/main/admin/system',
|
||||||
|
icon: 'dashboard',
|
||||||
|
// breadcrumbs: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}/*,
|
||||||
|
{
|
||||||
|
id: 'authentication',
|
||||||
|
title: 'Authentication',
|
||||||
|
type: 'group',
|
||||||
|
icon: 'icon-navigation',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 'login',
|
||||||
|
title: 'Login',
|
||||||
|
type: 'item',
|
||||||
|
classes: 'nav-item',
|
||||||
|
url: '/login',
|
||||||
|
icon: 'login',
|
||||||
|
target: true,
|
||||||
|
breadcrumbs: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'register',
|
||||||
|
title: 'Register',
|
||||||
|
type: 'item',
|
||||||
|
classes: 'nav-item',
|
||||||
|
url: '/register',
|
||||||
|
icon: 'profile',
|
||||||
|
target: true,
|
||||||
|
breadcrumbs: false
|
||||||
|
}*/
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
/*,
|
||||||
|
{
|
||||||
|
id: 'utilities',
|
||||||
|
title: 'UI Components',
|
||||||
|
type: 'group',
|
||||||
|
icon: 'icon-navigation',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 'typography',
|
||||||
|
title: 'Typography',
|
||||||
|
type: 'item',
|
||||||
|
classes: 'nav-item',
|
||||||
|
url: '/typography',
|
||||||
|
icon: 'font-size'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'color',
|
||||||
|
title: 'Colors',
|
||||||
|
type: 'item',
|
||||||
|
classes: 'nav-item',
|
||||||
|
url: '/color',
|
||||||
|
icon: 'bg-colors'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ant-icons',
|
||||||
|
title: 'Ant Icons',
|
||||||
|
type: 'item',
|
||||||
|
classes: 'nav-item',
|
||||||
|
url: 'https://ant.design/components/icon',
|
||||||
|
icon: 'ant-design',
|
||||||
|
target: true,
|
||||||
|
external: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: 'other',
|
||||||
|
title: 'Other',
|
||||||
|
type: 'group',
|
||||||
|
icon: 'icon-navigation',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 'sample-page',
|
||||||
|
title: 'Sample Page',
|
||||||
|
type: 'item',
|
||||||
|
url: '/sample-page',
|
||||||
|
classes: 'nav-item',
|
||||||
|
icon: 'chrome'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'document',
|
||||||
|
title: 'Document',
|
||||||
|
type: 'item',
|
||||||
|
classes: 'nav-item',
|
||||||
|
url: 'https://codedthemes.gitbook.io/mantis-angular/',
|
||||||
|
icon: 'question',
|
||||||
|
target: true,
|
||||||
|
external: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}*/
|
||||||
|
];
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<router-outlet></router-outlet>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-guest-layout',
|
||||||
|
imports: [RouterModule],
|
||||||
|
templateUrl: './guest-layout.component.html',
|
||||||
|
styleUrl: './guest-layout.component.scss'
|
||||||
|
})
|
||||||
|
export class GuestLayoutComponent {}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<!--<p>main.component works!</p>-->
|
||||||
|
|
||||||
|
<mat-toolbar class="fixed-top">
|
||||||
|
<button mat-raised-button routerLink="/" href="#">
|
||||||
|
My App
|
||||||
|
</button>
|
||||||
|
<span class="menu-spacer"></span>
|
||||||
|
<button mat-raised-button routerLink="tutorials">
|
||||||
|
Tutorials
|
||||||
|
</button>
|
||||||
|
@if (isLoggedIn) {
|
||||||
|
<button mat-raised-button routerLink="add-tutorial" >
|
||||||
|
Add tutorial
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
<span class="menu-spacer"></span>
|
||||||
|
@if (showAdminBoard) {
|
||||||
|
<button mat-raised-button routerLink="admin/welcome">
|
||||||
|
<mat-icon>manage_accounts</mat-icon>
|
||||||
|
Admin Bord
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (showAdminBoard) {
|
||||||
|
<button mat-raised-button routerLink="system" >
|
||||||
|
<mat-icon>settings_applications</mat-icon>
|
||||||
|
System
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
|
||||||
|
<span class="menu-spacer"></span>
|
||||||
|
@if (isLoggedIn) {
|
||||||
|
<button mat-raised-button routerLink="register">
|
||||||
|
<mat-icon>app_registration</mat-icon>
|
||||||
|
Register
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
@if (!isLoggedIn) {
|
||||||
|
<button mat-raised-button (click)="openDialog('100ms', '5ms')" >
|
||||||
|
<!-- <i antIcon type="bell" theme="outline"></i>-->
|
||||||
|
<!-- <mat-icon>login</mat-icon>-->
|
||||||
|
Login
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
@if (isLoggedIn) {
|
||||||
|
<button mat-raised-button routerLink="profile" >
|
||||||
|
<mat-icon>account_circle</mat-icon>
|
||||||
|
{{ username }}
|
||||||
|
</button>
|
||||||
|
<button mat-raised-button (click)="logout()">
|
||||||
|
<mat-icon>logout</mat-icon>
|
||||||
|
Logout
|
||||||
|
</button>
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</mat-toolbar>
|
||||||
|
|
||||||
|
|
||||||
|
<!--<app-nav-bar (NavCollapsedMob)="navMobClick()" (NavCollapse)="this.navCollapsed = !this.navCollapsed" />-->
|
||||||
|
<div class="router_outlet_padding">
|
||||||
|
<router-outlet/>
|
||||||
|
</div>
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
mat-toolbar{
|
||||||
|
background-color: rgba(153,153,153,0.16);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
}
|
||||||
|
.menu-spacer {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
.fixed-top {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1000; // Ensure toolbar stays above other content
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { MainComponent } from './main.component';
|
||||||
|
|
||||||
|
describe('MainComponent', () => {
|
||||||
|
let component: MainComponent;
|
||||||
|
let fixture: ComponentFixture<MainComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [MainComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(MainComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user