feat(layout): enhance topbar with customizable templates and full-page support
- Updated app.layout.component.html to include start, center, and end templates for the topbar. - Modified app.layout.component.ts to manage new template references and added isFullPage getter. - Refactored app.topbar.component.html to utilize new templates and improved layout structure. - Enhanced app.topbar.component.ts to accept new input properties for templates. - Updated layout.service.ts to manage full-page state and new topbar slots. - Added new payment bridge services for POS functionality. - Introduced greater validator for form validation. - Improved dialog component to support mobile drawer and responsive design. - Updated styles for better mobile support and layout adjustments. - Added new main menu sidebar for POS with dynamic content.
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
<div class="layout-wrapper" [ngClass]="containerClass">
|
||||
<app-topbar [showMenu]="showMenu()">
|
||||
<ng-container [ngTemplateOutlet]="topBarMoreAction"></ng-container>
|
||||
</app-topbar>
|
||||
<app-topbar
|
||||
[showMenu]="showMenu()"
|
||||
[startTemplate]="topBarStartAction"
|
||||
[centerTemplate]="topBarCenterAction"
|
||||
[endTemplate]="topBarEndAction || topBarMoreAction"
|
||||
/>
|
||||
@if (fullLoading) {
|
||||
<div class="flex justify-center align-items-center grow items-center">
|
||||
<p-progressSpinner></p-progressSpinner>
|
||||
@@ -10,12 +13,12 @@
|
||||
@if (showMenu()) {
|
||||
<app-sidebar></app-sidebar>
|
||||
}
|
||||
<div [class]="`layout-main-container ${!showMenu() ? 'hideMenu' : ''} grow`">
|
||||
<div [class]="`layout-main-container ${!showMenu() ? 'hideMenu' : ''} grow ${isFullPage ? 'isFullPage' : ''}`">
|
||||
<div class="layout-main flex flex-col gap-4">
|
||||
@if (showBreadcrumb) {
|
||||
<app-breadcrumb class="rounded-md overflow-hidden shrink-0" />
|
||||
}
|
||||
<div [class]="`rounded-md flex flex-col grow ${isFixedContentSize ? 'overflow-auto' : 'overflow-hidden'}`">
|
||||
<div [class]="`rounded-md flex flex-col grow`">
|
||||
<!-- style="container-type: size" -->
|
||||
<div class="h-full">
|
||||
@if (content) {
|
||||
|
||||
@@ -47,6 +47,9 @@ export class AppLayout {
|
||||
private authService = inject(AuthService);
|
||||
|
||||
topBarMoreAction?: Maybe<TemplateRef<any>> = null;
|
||||
topBarStartAction?: Maybe<TemplateRef<any>> = null;
|
||||
topBarCenterAction?: Maybe<TemplateRef<any>> = null;
|
||||
topBarEndAction?: Maybe<TemplateRef<any>> = null;
|
||||
|
||||
constructor(
|
||||
public layoutService: LayoutService,
|
||||
@@ -137,6 +140,9 @@ export class AppLayout {
|
||||
get isFixedContentSize(): boolean {
|
||||
return this.layoutService.isFixedContentSize() || false;
|
||||
}
|
||||
get isFullPage(): boolean {
|
||||
return this.layoutService.isFullPage() || false;
|
||||
}
|
||||
|
||||
showMenu = computed(() => {
|
||||
return this.layoutService.menuItems().length > 0;
|
||||
@@ -144,6 +150,9 @@ export class AppLayout {
|
||||
|
||||
ngOnInit() {
|
||||
this.layoutService.headerSlot$.subscribe((tpl) => (this.topBarMoreAction = tpl));
|
||||
this.layoutService.topbarStartSlot$.subscribe((tpl) => (this.topBarStartAction = tpl));
|
||||
this.layoutService.topbarCenterSlot$.subscribe((tpl) => (this.topBarCenterAction = tpl));
|
||||
this.layoutService.topbarEndSlot$.subscribe((tpl) => (this.topBarEndAction = tpl));
|
||||
|
||||
if (window.location.pathname === '/') {
|
||||
if (!this.authService.currentAccount()) {
|
||||
|
||||
@@ -1,43 +1,44 @@
|
||||
<div class="layout-topbar shrink-0">
|
||||
<div class="layout-topbar-logo-container">
|
||||
@if (showMenu) {
|
||||
<button class="layout-menu-button layout-topbar-action" (click)="layoutService.onMenuToggle()">
|
||||
<i class="pi pi-bars"></i>
|
||||
</button>
|
||||
}
|
||||
<div class="layout-topbar-logo">
|
||||
<img [src]="logo" width="32" />
|
||||
<span class="text-xl">{{ panelTitle() }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layout-topbar-actions items-center">
|
||||
<ng-content></ng-content>
|
||||
<div class="layout-config-menu">
|
||||
<button type="button" class="layout-topbar-action" (click)="toggleDarkMode()">
|
||||
<i
|
||||
[ngClass]="{ 'pi ': true, 'pi-moon': layoutService.isDarkTheme(), 'pi-sun': !layoutService.isDarkTheme() }"
|
||||
></i>
|
||||
</button>
|
||||
<!-- <div class="relative">
|
||||
<button
|
||||
class="layout-topbar-action layout-topbar-action-highlight"
|
||||
pStyleClass="@next"
|
||||
enterFromClass="hidden"
|
||||
enterActiveClass="animate-scalein"
|
||||
leaveToClass="hidden"
|
||||
leaveActiveClass="animate-fadeout"
|
||||
[hideOnOutsideClick]="true"
|
||||
>
|
||||
<i class="pi pi-palette"></i>
|
||||
<p-toolbar>
|
||||
<ng-template #start>
|
||||
@if (startTemplate) {
|
||||
<ng-container [ngTemplateOutlet]="startTemplate"></ng-container>
|
||||
} @else {
|
||||
@if (showMenu) {
|
||||
<button class="layout-menu-button layout-topbar-action" (click)="layoutService.onMenuToggle()">
|
||||
<i class="pi pi-bars"></i>
|
||||
</button>
|
||||
<app-configurator></app-configurator>
|
||||
</div> -->
|
||||
</div>
|
||||
}
|
||||
<div class="flex items-center gap-2">
|
||||
<img [src]="logo" width="32" />
|
||||
<span class="text-xl">{{ panelTitle() }}</span>
|
||||
</div>
|
||||
}
|
||||
</ng-template>
|
||||
<ng-template #center>
|
||||
@if (centerTemplate) {
|
||||
<ng-container [ngTemplateOutlet]="centerTemplate"></ng-container>
|
||||
}
|
||||
</ng-template>
|
||||
<ng-template #end>
|
||||
@if (endTemplate) {
|
||||
<ng-container [ngTemplateOutlet]="endTemplate"></ng-container>
|
||||
} @else {
|
||||
<div class="flex items-center gap-2">
|
||||
<ng-content></ng-content>
|
||||
<p-button
|
||||
type="button"
|
||||
[icon]="`pi ${layoutService.isDarkTheme() ? 'pi-moon' : 'pi-sun'}`"
|
||||
text
|
||||
(click)="toggleDarkMode()"
|
||||
>
|
||||
<i [ngClass]="{}"></i>
|
||||
</p-button>
|
||||
|
||||
<div class="">
|
||||
<p-menu #menu [model]="profileMenuItems" [popup]="true" />
|
||||
<p-button (click)="menu.toggle($event)" icon="pi pi-user" text severity="contrast" size="large" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="">
|
||||
<p-menu #menu [model]="profileMenuItems" [popup]="true" />
|
||||
<p-button (click)="menu.toggle($event)" icon="pi pi-user" text severity="contrast" size="large" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</ng-template>
|
||||
</p-toolbar>
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
import { AuthService } from '@/core/services/auth.service';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, computed, inject, Input } from '@angular/core';
|
||||
import { Component, computed, inject, Input, TemplateRef } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { MenuItem } from 'primeng/api';
|
||||
import { Button } from 'primeng/button';
|
||||
import { Button, ButtonIcon } from 'primeng/button';
|
||||
import { MenuModule } from 'primeng/menu';
|
||||
import { StyleClassModule } from 'primeng/styleclass';
|
||||
import { Toolbar } from 'primeng/toolbar';
|
||||
import images from 'src/assets/images';
|
||||
import { LayoutService } from '../service/layout.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-topbar',
|
||||
standalone: true,
|
||||
imports: [RouterModule, CommonModule, StyleClassModule, MenuModule, Button],
|
||||
imports: [RouterModule, CommonModule, StyleClassModule, MenuModule, Button, Toolbar, ButtonIcon],
|
||||
templateUrl: './app.topbar.component.html',
|
||||
})
|
||||
export class AppTopbar {
|
||||
@Input() showMenu: boolean = false;
|
||||
@Input() startTemplate?: TemplateRef<any> | null = null;
|
||||
@Input() centerTemplate?: TemplateRef<any> | null = null;
|
||||
@Input() endTemplate?: TemplateRef<any> | null = null;
|
||||
|
||||
constructor(public layoutService: LayoutService) {}
|
||||
private authService: AuthService = inject(AuthService);
|
||||
|
||||
@@ -21,6 +21,7 @@ interface LayoutState {
|
||||
staticMenuMobileActive?: boolean;
|
||||
menuHoverActive?: boolean;
|
||||
isFixedContentSize?: boolean;
|
||||
isFullPage?: boolean;
|
||||
}
|
||||
|
||||
interface MenuChangeEvent {
|
||||
@@ -47,6 +48,7 @@ export class LayoutService {
|
||||
staticMenuMobileActive: false,
|
||||
menuHoverActive: false,
|
||||
isFixedContentSize: true,
|
||||
isFullPage: false,
|
||||
};
|
||||
|
||||
layoutConfig = signal<layoutConfig>(this._config);
|
||||
@@ -90,6 +92,7 @@ export class LayoutService {
|
||||
isOverlay = computed(() => this.layoutConfig().menuMode === 'overlay');
|
||||
|
||||
isFixedContentSize = computed(() => this.layoutState().isFixedContentSize);
|
||||
isFullPage = computed(() => this.layoutState().isFullPage);
|
||||
|
||||
transitionComplete = signal<boolean>(false);
|
||||
|
||||
@@ -144,6 +147,13 @@ export class LayoutService {
|
||||
}));
|
||||
}
|
||||
|
||||
changeIsFullPage(status: boolean) {
|
||||
this.layoutState.update((prev) => ({
|
||||
...prev,
|
||||
isFullPage: status,
|
||||
}));
|
||||
}
|
||||
|
||||
toggleDarkMode(config?: layoutConfig): void {
|
||||
const _config = config || this.layoutConfig();
|
||||
localStorage.setItem('isDarkTheme', JSON.stringify(_config.darkTheme));
|
||||
@@ -221,8 +231,28 @@ export class LayoutService {
|
||||
|
||||
private headerSlot = new BehaviorSubject<TemplateRef<any> | null>(null);
|
||||
headerSlot$ = this.headerSlot.asObservable();
|
||||
private topbarStartSlot = new BehaviorSubject<TemplateRef<any> | null>(null);
|
||||
topbarStartSlot$ = this.topbarStartSlot.asObservable();
|
||||
private topbarCenterSlot = new BehaviorSubject<TemplateRef<any> | null>(null);
|
||||
topbarCenterSlot$ = this.topbarCenterSlot.asObservable();
|
||||
private topbarEndSlot = new BehaviorSubject<TemplateRef<any> | null>(null);
|
||||
topbarEndSlot$ = this.topbarEndSlot.asObservable();
|
||||
|
||||
setHeaderSlot(tpl: TemplateRef<any> | null) {
|
||||
// Backward-compatible alias for topbar end slot.
|
||||
this.setTopbarEndSlot(tpl);
|
||||
this.headerSlot.next(tpl);
|
||||
}
|
||||
|
||||
setTopbarStartSlot(tpl: TemplateRef<any> | null) {
|
||||
this.topbarStartSlot.next(tpl);
|
||||
}
|
||||
|
||||
setTopbarCenterSlot(tpl: TemplateRef<any> | null) {
|
||||
this.topbarCenterSlot.next(tpl);
|
||||
}
|
||||
|
||||
setTopbarEndSlot(tpl: TemplateRef<any> | null) {
|
||||
this.topbarEndSlot.next(tpl);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user