Files
jambotron/jambotron-ui/src/app/components/vertical-nav.component/vertical-nav.component.ts
T
2025-08-14 18:50:16 +03:00

112 lines
3.0 KiB
TypeScript

import {
Component,
computed,
CUSTOM_ELEMENTS_SCHEMA,
EventEmitter,
inject,
Input,
OnInit,
Output,
signal
} from '@angular/core';
import {Route, Router, RouterLink, RouterLinkActive} from '@angular/router';
import {MatListItem, MatListItemIcon, MatListItemTitle, MatNavList} from '@angular/material/list';
import {NgForOf} from '@angular/common';
import {MatIconButton} from '@angular/material/button';
import {MatTooltip} from '@angular/material/tooltip';
import {MatIcon} from '@angular/material/icon';
import {adminRouting} from '../../modules/admin-module/admin.routing';
export interface NavItem {
path: string; // absolute path like /dashboard
title: string; // label to show
icon?: string; // material icon name
exact?: boolean; // whether to match exactly
}
@Component({
selector: 'app-vertical-nav',
imports: [
MatTooltip,
MatIcon,
MatListItemIcon,
MatListItemTitle,
RouterLinkActive,
RouterLink,
MatListItem,
MatNavList,
NgForOf,
MatIconButton,
],
templateUrl: './vertical-nav.component.html',
styleUrl: './vertical-nav.component.scss',
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class VerticalNavComponent implements OnInit{
private router = inject(Router);
// Optional: if you want to pass items directly instead of deriving from routes
@Input() items: NavItem[] | null = null;
// Optional: pass a specific Route[] (e.g., ADMIN_ROUTES). If not provided, uses router.config.
@Input() routes: Route[] = [];
// Optional: prepend a base path (e.g., '/admin') when using feature routes.
@Input() basePath = '';
// Sidebar state (expanded/collapsed)
opened = signal(true);
navItems = signal<NavItem[]>([]);
readonly hasItems = computed(() => (this.items?.length ?? this.navItems().length) > 0);
@Output() collapsedChange = new EventEmitter<boolean>();
constructor() {
}
ngOnInit(): void {
this.navItems.set(this.deriveFromRoutes(this.routes, this.basePath));
}
toggle(): void {
this.opened.update(v => !v);
this.collapsedChange.emit(!this.opened());
}
private deriveFromRoutes(routes: Route[], base: string): NavItem[] {
// Flatten one level; you can make this recursive if needed
const items: NavItem[] = [];
for (const r of routes) {
if (!r || r.path === '**') continue;
const data = (r as any).data || {};
const seg = r.path || '';
const nextBase = [base, seg].filter(Boolean).join('/');
/* // Recurse into children if present (common in feature modules)
if (r.children && r.children.length) {
items.push(...this.deriveFromRoutes(r.children, nextBase));
}
*/
if (data.nav === false) continue;
const title = data.title as string | undefined;
if (!title) continue;
const icon = data.icon as string | undefined;
const full = '/' + nextBase.replace(/\/+/g, '/');
items.push({ path: full, title, icon, exact: true });
}
return items;
}
}