work in progress

This commit is contained in:
Igor Hrenowitsch Propisnov 2024-09-09 21:38:09 +02:00
parent 53311438ae
commit eb33c9bbdf
2 changed files with 171 additions and 215 deletions

View File

@ -1,156 +1,92 @@
<div class="flex h-screen overflow-hidden"> <!-- app.component.html -->
<div <div class="flex flex-col h-screen overflow-hidden">
[ngStyle]="navigation" <!-- Header -->
[class]=" <header class="w-full navbar bg-primary text-primary-content z-20">
isCollapsed <div class="flex-1">
? 'bg-primary w-0 md:w-20 transition-all duration-300 ease-in-out shadow-[5px_0_20px_rgba(0,0,0,0.5)]' <a class="btn btn-ghost normal-case text-xl text-primary-content">
: showMobileMenu [APP-NAME]
? 'bg-primary w-64 transition-all duration-300 ease-in-out shadow-[5px_0_20px_rgba(0,0,0,0.5)]' </a>
: isDesktopCollapsed
? 'bg-primary w-48 md:w-14 transition-all duration-300 ease-in-out shadow-[5px_0_20px_rgba(0,0,0,0.5)]'
: 'bg-primary w-48 md:w-48 transition-all duration-300 ease-in-out shadow-[5px_0_20px_rgba(0,0,0,0.5)]'
"
class="transform h-full z-20 overflow-y-auto fixed md:relative flex flex-col">
<div
[ngClass]="showMobileMenu ? 'justify-center' : 'justify-between'"
[ngStyle]="navigation"
class="p-1 w-full h-16 z-50 bg-base-100 flex items-center relative">
<div class="flex items-center justify-center h-full w-full">
<div class="flex items-center space-x-4">
@if (!isCollapsed && !isDesktopCollapsed) {
<div class="text-primary">LOGO</div>
}
@if (!isCollapsed && !showMobileMenu) {
<button
(click)="toggleDesktopSidebar()"
class="flex items-center justify-center w-10 h-10 rounded-full">
@if (isDesktopCollapsed) {
<svg
class="stroke-current text-primary w-6 h-6"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="3">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m8.25 4.5 7.5 7.5-7.5 7.5" />
</svg>
} @else {
<svg
class="stroke-current text-primary w-6 h-6"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="3">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15.75 19.5 8.25 12l7.5-7.5" />
</svg>
}
</button>
}
</div>
</div>
</div> </div>
<ul class="m-1"> <div class="flex-none lg:hidden">
<li <label for="my-drawer" class="btn btn-square btn-ghost drawer-button">
class="cursor-pointer rounded-btn mt-2" <svg
[ngClass]="{ xmlns="http://www.w3.org/2000/svg"
'bg-base-100 text-primary': item.active, fill="none"
'text-primary-content hover:text-accent-content hover:bg-accent': viewBox="0 0 24 24"
!item.active class="inline-block w-6 h-6 stroke-current">
}" <path
(click)="setActive(item)" stroke-linecap="round"
(keydown.enter)="setActive(item)" stroke-linejoin="round"
(keydown.space)="setActive(item)" stroke-width="2"
tabindex="0" d="M4 6h16M4 12h16M4 18h16"></path>
role="button" </svg>
*ngFor="let item of menuItems"> </label>
<div </div>
class="flex justify-center p-1" <div class="flex-none hidden lg:block">
*ngIf="isDesktopCollapsed && !showMobileMenu"> <!-- Zusätzliche Header-Elemente für große Bildschirme -->
<span class="p-1" [innerHTML]="item.icon"></span> </div>
</div> </header>
<div <!-- Hauptcontainer -->
class="flex items-center rounded-btn justify-between cursor-pointer px-1 py-2" <div class="drawer lg:drawer-open flex-1 overflow-hidden">
*ngIf="!isDesktopCollapsed || showMobileMenu"> <input id="my-drawer" type="checkbox" class="drawer-toggle" />
<div class="flex items-center">
<span [innerHTML]="item.icon" class="mx-2"></span> <!-- Hauptinhalt -->
<span>{{ item.name }}</span> <div class="drawer-content flex flex-col bg-base-100">
<main class="flex-1 overflow-y-auto p-4">
<div class="w-full h-full flex items-center justify-center">
<div class="w-full max-w-5xl">
<router-outlet></router-outlet>
</div> </div>
</div> </div>
</li> </main>
</ul> </div>
<ul class="m-1 mt-auto">
<li <!-- Drawer -->
class="cursor-pointer bg-base-100 text-base-content rounded-btn mb-2" <div class="drawer-side h-full">
*ngFor="let item of bottomMenuItems" <label for="my-drawer" class="drawer-overlay"></label>
(click)="item.action ? item.action() : null" <aside class="bg-primary text-primary-content w-64 h-full flex flex-col">
(keydown.enter)="item.action ? item.action() : null" <div class="flex-1 overflow-y-auto py-4 pt-0">
(keydown.space)="item.action ? item.action() : null" <ul class="w-full p-0 m-0 [&_li>*]:rounded-none">
tabindex="0" <ng-container *ngFor="let item of menuItems">
role="button"> <li class="w-full">
<div <a
class="flex justify-center p-1" [routerLink]="item.route"
*ngIf="isDesktopCollapsed && !showMobileMenu"> routerLinkActive="bg-base-100 text-base-content"
<span class="p-1" [innerHTML]="item.icon"></span> [routerLinkActiveOptions]="{ exact: false }"
class="flex items-center w-full px-4 py-3 text-base-content transition-colors duration-200 ease-in-out focus:outline-none"
role="menuitem"
tabindex="0"
(keydown.enter)="
$event.preventDefault(); navigateTo(item.route)
">
<span
class="flex-shrink-0 w-6 h-6 mr-3"
[innerHTML]="item.icon"></span>
<span class="flex-grow">{{ item.name }}</span>
</a>
</li>
</ng-container>
</ul>
</div> </div>
<div class="p-4">
<div <ul class="menu w-full">
class="flex items-center rounded-btn justify-between cursor-pointer px-1 py-2" <ng-container *ngFor="let item of bottomMenuItems">
*ngIf="!isDesktopCollapsed || showMobileMenu"> <li>
<div class="flex items-center"> <button
<span [innerHTML]="item.icon" class="mx-2"></span> (click)="executeAction(item)"
<span>{{ item.name }}</span> (keydown.enter)="executeAction(item)"
</div> class="flex items-center space-x-2 hover:bg-primary-focus focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-focus w-full text-left"
role="menuitem"
tabindex="0">
<span [innerHTML]="item.icon"></span>
<span>{{ item.name }}</span>
</button>
</li>
</ng-container>
</ul>
</div> </div>
</li> </aside>
</ul>
</div>
<div class="flex flex-col flex-grow">
<header
[ngStyle]="navigation"
class="p-4 z-0 md:z-20 relative bg-primary text-primary-content flex items-center h-16 shadow-[0_5px_20px_rgba(0,0,0,0.5)]">
<div class="w-10 flex items-center justify-center md:hidden">
<label class="btn btn-ghost swap swap-rotate">
<input
type="checkbox"
(change)="toggleSidebar()"
[checked]="!isCollapsed" />
<svg
class="swap-off fill-current"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 512 512">
<path
d="M64,384H448V341.33H64Zm0-106.67H448V234.67H64ZM64,128v42.67H448V128Z" />
</svg>
<svg
class="swap-on fill-current"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 512 512">
<polygon
points="400 145.49 366.51 112 256 222.51 145.49 112 112 145.49 222.51 256 112 366.51 145.49 400 256 289.49 366.51 400 400 366.51 289.49 256 400 145.49" />
</svg>
</label>
</div>
</header>
<div [ngStyle]="mainContent" class="overflow-y-auto h-screen">
<router-outlet></router-outlet>
</div> </div>
</div> </div>
<div
*ngIf="!isCollapsed"
class="fixed inset-0 bg-black bg-opacity-50 z-10 md:hidden"
(click)="toggleSidebar()"></div>
</div> </div>

View File

@ -3,11 +3,18 @@ import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
ElementRef, ElementRef,
HostListener,
OnInit, OnInit,
} from '@angular/core'; } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { Router, RouterOutlet } from '@angular/router'; import {
ActivatedRoute,
NavigationEnd,
Router,
RouterModule,
RouterOutlet,
} from '@angular/router';
import { filter } from 'rxjs';
import { SuccessDtoApiModel } from '../../api'; import { SuccessDtoApiModel } from '../../api';
import { BackgroundPatternService, ThemeService } from '../../shared/service'; import { BackgroundPatternService, ThemeService } from '../../shared/service';
@ -30,7 +37,7 @@ interface BottomMenuItem {
selector: 'app-layout', selector: 'app-layout',
standalone: true, standalone: true,
providers: [], providers: [],
imports: [RouterOutlet, CommonModule], imports: [RouterOutlet, CommonModule, RouterModule],
templateUrl: './layout.component.html', templateUrl: './layout.component.html',
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
@ -73,95 +80,108 @@ export class LayoutComponent implements OnInit {
private readonly sanitizer: DomSanitizer, private readonly sanitizer: DomSanitizer,
private readonly router: Router, private readonly router: Router,
private readonly backgroundPatternService: BackgroundPatternService, private readonly backgroundPatternService: BackgroundPatternService,
private readonly route: ActivatedRoute,
private readonly themeService: ThemeService, private readonly themeService: ThemeService,
private readonly el: ElementRef, private readonly el: ElementRef,
private readonly authService: AuthService private readonly authService: AuthService
) {} ) {}
public ngOnInit(): void { public ngOnInit(): void {
this.router.events
.pipe(filter((event) => event instanceof NavigationEnd))
.subscribe(() => {
this.setActiveItemBasedOnRoute();
});
// Initial set
this.setActiveItemBasedOnRoute(); this.setActiveItemBasedOnRoute();
this.router.events.subscribe(() => {
this.setActiveItemBasedOnRoute();
});
this.setBackground();
this.onResize();
} }
@HostListener('window:resize', ['$event']) public navigateTo(route: string): void {
public onResize(): void { this.router.navigate([route]);
if (window.innerWidth >= 768) { }
this.showMobileMenu = false;
this.isCollapsed = false; public executeAction(item: BottomMenuItem): void {
} else { if (item.action) {
this.isDesktopCollapsed = false; item.action();
this.isCollapsed = true;
this.showMobileMenu = false;
} }
} }
public setBackground(): void { // @HostListener('window:resize', ['$event'])
const theme = this.themeService.getTheme(); // public onResize(): void {
let opacity: number; // if (window.innerWidth >= 768) {
// this.showMobileMenu = false;
// this.isCollapsed = false;
// } else {
// this.isDesktopCollapsed = false;
// this.isCollapsed = true;
// this.showMobileMenu = false;
// }
// }
if (theme === 'dark') { // public setBackground(): void {
opacity = 0.05; // const theme = this.themeService.getTheme();
} else { // let opacity: number;
opacity = 0.1;
}
const colorPrimary = getComputedStyle( // if (theme === 'dark') {
this.el.nativeElement // opacity = 0.05;
).getPropertyValue('--p'); // } else {
// opacity = 0.1;
// }
const colorPrimaryC = getComputedStyle( // const colorPrimary = getComputedStyle(
this.el.nativeElement // this.el.nativeElement
).getPropertyValue('--pc'); // ).getPropertyValue('--p');
const svgUrlMainContent = this.backgroundPatternService.getPlusPattern( // const colorPrimaryC = getComputedStyle(
colorPrimary, // this.el.nativeElement
opacity // ).getPropertyValue('--pc');
);
const svgUrlNavigation = this.backgroundPatternService.getBankNotePattern(
colorPrimaryC,
opacity
);
this.mainContent = { // const svgUrlMainContent = this.backgroundPatternService.getPlusPattern(
'background-image': `url("${svgUrlMainContent}")`, // colorPrimary,
}; // opacity
this.navigation = { // );
'background-image': `url("${svgUrlNavigation}")`, // const svgUrlNavigation = this.backgroundPatternService.getBankNotePattern(
}; // colorPrimaryC,
} // opacity
// );
public toggleSidebar(): void { // this.mainContent = {
if (window.innerWidth < 768) { // 'background-image': `url("${svgUrlMainContent}")`,
this.showMobileMenu = !this.showMobileMenu; // };
this.isCollapsed = !this.showMobileMenu; // this.navigation = {
} else { // 'background-image': `url("${svgUrlNavigation}")`,
this.isDesktopCollapsed = !this.isDesktopCollapsed; // };
} // }
}
public toggleDesktopSidebar(): void { // public toggleSidebar(): void {
this.isDesktopCollapsed = !this.isDesktopCollapsed; // if (window.innerWidth < 768) {
} // this.showMobileMenu = !this.showMobileMenu;
// this.isCollapsed = !this.showMobileMenu;
// } else {
// this.isDesktopCollapsed = !this.isDesktopCollapsed;
// }
// }
public setActive(item: TopMenuItem): void { // public toggleDesktopSidebar(): void {
this.menuItems.forEach((menu: TopMenuItem) => { // this.isDesktopCollapsed = !this.isDesktopCollapsed;
menu.active = false; // }
});
this.router.navigate([item.route]); // public setActive(item: TopMenuItem): void {
if (!this.isCollapsed && this.showMobileMenu) { // this.menuItems.forEach((menu: TopMenuItem) => {
this.toggleSidebar(); // menu.active = false;
} // });
} // this.router.navigate([item.route]);
// if (!this.isCollapsed && this.showMobileMenu) {
// this.toggleSidebar();
// }
// }
private setActiveItemBasedOnRoute(): void { private setActiveItemBasedOnRoute(): void {
const url = this.router.url; const currentRoute = this.router.url;
this.menuItems.forEach((item: TopMenuItem) => { this.menuItems.forEach((item: TopMenuItem) => {
item.active = url.startsWith(item.route); item.active = currentRoute.startsWith(item.route);
}); });
} }