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:
+2
-2
@@ -166,9 +166,9 @@ export class AmountPercentageInputComponent {
|
||||
|
||||
private prepareLabel(isPercentageType: boolean) {
|
||||
if (isPercentageType) {
|
||||
return `${this.label} (${formatWithCurrency(this.amountControl.value || 0)})`;
|
||||
return `${this.label} (معادل ${formatWithCurrency(this.amountControl.value || 0)})`;
|
||||
}
|
||||
return `${this.label} (${this.percentageControl.value || 0} درصد)`;
|
||||
return `${this.label} (معادل ${this.percentageControl.value || 0} درصد)`;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<ng-template #dialogContent>
|
||||
<ng-content></ng-content>
|
||||
</ng-template>
|
||||
|
||||
@if (mobileDrawer && isMobile) {
|
||||
<p-drawer
|
||||
[header]="header"
|
||||
[visible]="visible"
|
||||
position="bottom"
|
||||
[modal]="modal"
|
||||
[closable]="closable"
|
||||
[style]="{ 'max-height': mobileDrawerHeight, height: 'auto' }"
|
||||
styleClass="shared-mobile-drawer"
|
||||
(visibleChange)="onVisibilityChange($event)"
|
||||
(onHide)="onHide.emit($event)"
|
||||
>
|
||||
<ng-container [ngTemplateOutlet]="dialogContent"></ng-container>
|
||||
</p-drawer>
|
||||
} @else {
|
||||
<p-dialog
|
||||
[header]="header"
|
||||
[visible]="visible"
|
||||
[modal]="modal"
|
||||
[style]="style"
|
||||
[closable]="closable"
|
||||
[draggable]="draggable"
|
||||
[breakpoints]="breakpoints"
|
||||
(visibleChange)="onVisibilityChange($event)"
|
||||
(onHide)="onHide.emit($event)"
|
||||
>
|
||||
<ng-container [ngTemplateOutlet]="dialogContent"></ng-container>
|
||||
</p-dialog>
|
||||
}
|
||||
@@ -1,25 +1,25 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { NgTemplateOutlet } from '@angular/common';
|
||||
import { Component, EventEmitter, HostListener, Input, OnInit, Output } from '@angular/core';
|
||||
import { Dialog } from 'primeng/dialog';
|
||||
import { Drawer } from 'primeng/drawer';
|
||||
|
||||
@Component({
|
||||
selector: 'shared-dialog',
|
||||
template: `
|
||||
<p-dialog
|
||||
[header]="header"
|
||||
[(visible)]="visible"
|
||||
[modal]="modal"
|
||||
[style]="style"
|
||||
[closable]="closable"
|
||||
[draggable]="draggable"
|
||||
[breakpoints]="breakpoints"
|
||||
(onHide)="onHide.emit($event)"
|
||||
>
|
||||
<ng-content />
|
||||
</p-dialog>
|
||||
`,
|
||||
imports: [Dialog],
|
||||
templateUrl: './dialog.component.html',
|
||||
imports: [Dialog, Drawer, NgTemplateOutlet],
|
||||
styles: [
|
||||
`
|
||||
:host ::ng-deep .shared-mobile-drawer.p-drawer-bottom {
|
||||
border-top-left-radius: 16px;
|
||||
border-top-right-radius: 16px;
|
||||
}
|
||||
:host ::ng-deep .shared-mobile-drawer .p-drawer-content {
|
||||
padding-bottom: calc(1rem + env(safe-area-inset-bottom));
|
||||
}
|
||||
`,
|
||||
],
|
||||
})
|
||||
export class SharedDialogComponent {
|
||||
export class SharedDialogComponent implements OnInit {
|
||||
@Input() header = '';
|
||||
@Input() visible = false;
|
||||
@Output() visibleChange = new EventEmitter<boolean>();
|
||||
@@ -29,6 +29,29 @@ export class SharedDialogComponent {
|
||||
@Input() draggable = false;
|
||||
@Input() style: Record<string, string> | undefined;
|
||||
@Input() breakpoints: Record<string, string> | undefined;
|
||||
@Input() mobileBreakpoint = 768;
|
||||
@Input() mobileDrawer = true;
|
||||
@Input() mobileDrawerHeight = '90svh';
|
||||
|
||||
@Output() onHide = new EventEmitter<any>();
|
||||
|
||||
isMobile = false;
|
||||
|
||||
ngOnInit() {
|
||||
this.updateViewportMode();
|
||||
}
|
||||
|
||||
@HostListener('window:resize')
|
||||
onResize() {
|
||||
this.updateViewportMode();
|
||||
}
|
||||
|
||||
onVisibilityChange(nextValue: boolean) {
|
||||
this.visible = nextValue;
|
||||
this.visibleChange.emit(nextValue);
|
||||
}
|
||||
|
||||
private updateViewportMode() {
|
||||
this.isMobile = typeof window !== 'undefined' && window.innerWidth <= this.mobileBreakpoint;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="flex justify-end gap-2">
|
||||
<p-button [label]="cancelLabel" severity="secondary" (click)="cancel()" />
|
||||
<p-button [label]="submitLabel" type="submit" [loading]="loading" (onClick)="submit()" />
|
||||
<p-button [label]="submitLabel" type="submit" [disabled]="disabled" [loading]="loading" (onClick)="submit()" />
|
||||
</div>
|
||||
|
||||
@@ -10,6 +10,7 @@ export class FormFooterActionsComponent {
|
||||
@Input() submitLabel = 'تایید';
|
||||
@Input() cancelLabel = 'لغو';
|
||||
@Input() loading = false;
|
||||
@Input() disabled = false;
|
||||
@Output() onSubmit = new EventEmitter<void>();
|
||||
@Output() onCancel = new EventEmitter<void>();
|
||||
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
<uikit-field [label]="label" [name]="name" [control]="control" [showLabel]="!!label" [showErrors]="showErrors">
|
||||
@if (labelSuffix) {
|
||||
<ng-template #labelView>
|
||||
<div class="flex gap-1 items-center">
|
||||
<uikit-label [name]="name">
|
||||
@if (labelTextView) {
|
||||
<ng-container [ngTemplateOutlet]="labelTextView"></ng-container>
|
||||
} @else {
|
||||
{{ label }}
|
||||
}
|
||||
</uikit-label>
|
||||
<ng-container [ngTemplateOutlet]="labelSuffix"></ng-container>
|
||||
</div>
|
||||
</ng-template>
|
||||
}
|
||||
@if (type === "switch") {
|
||||
<p-toggleSwitch [formControl]="control" />
|
||||
<p-toggleSwitch [attr.disabled]="disabled" [formControl]="control" />
|
||||
} @else {
|
||||
<p-inputgroup>
|
||||
<!-- [minlength]="minlength || null" -->
|
||||
@@ -13,6 +27,7 @@
|
||||
[attr.placeholder]="preparedPlaceholder"
|
||||
[attr.type]="htmlType"
|
||||
[attr.autocomplete]="autocomplete"
|
||||
[attr.disabled]="disabled"
|
||||
[class]="` w-full ${size === 'large' ? 'p-inputtext-lg' : size === 'small' ? 'p-inputtext-sm' : ''}`"
|
||||
[required]="isRequired"
|
||||
[invalid]="control.invalid && (control.touched || control.dirty)"
|
||||
@@ -30,6 +45,7 @@
|
||||
[attr.inputmode]="inputMode"
|
||||
[attr.maxlength]="preparedMaxLength || null"
|
||||
[attr.type]="htmlType"
|
||||
[attr.disabled]="disabled"
|
||||
[attr.autocomplete]="autocomplete"
|
||||
[classList]="
|
||||
[
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Maybe } from '@/core';
|
||||
import { ToastService } from '@/core/services/toast.service';
|
||||
import { UikitLabelComponent } from '@/uikit';
|
||||
import { UikitFieldComponent } from '@/uikit/uikit-field.component';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import {
|
||||
@@ -35,6 +36,7 @@ import { ToggleSwitch } from 'primeng/toggleswitch';
|
||||
InputNumberModule,
|
||||
KeyFilterModule,
|
||||
InputMaskModule,
|
||||
UikitLabelComponent,
|
||||
],
|
||||
templateUrl: './input.component.html',
|
||||
})
|
||||
@@ -69,6 +71,8 @@ export class InputComponent {
|
||||
@Output() blur = new EventEmitter<void>();
|
||||
|
||||
@ContentChild('suffixTemp', { static: true }) suffixTemp!: TemplateRef<any> | null;
|
||||
@ContentChild('labelSuffix', { static: false }) labelSuffix!: TemplateRef<any> | null;
|
||||
@ContentChild('labelTextView', { static: false }) labelTextView!: TemplateRef<any> | null;
|
||||
|
||||
private readonly toastService = inject(ToastService);
|
||||
|
||||
@@ -202,14 +206,14 @@ export class InputComponent {
|
||||
const minValidator = (this.min || this.min === 0) && parseFloat(value) < this.min!;
|
||||
const maxValidator = (this.max || this.max === 0) && parseFloat(value) > this.max;
|
||||
if (minValidator || maxValidator) {
|
||||
if (minValidator) {
|
||||
this.toastService.warn({
|
||||
text: `مقدار ${this.label} نمیتواند بیشتر از ${this.min} باشد.`,
|
||||
});
|
||||
}
|
||||
if (maxValidator) {
|
||||
this.toastService.warn({
|
||||
text: `مقدار ${this.label} نمیتواند کمتر از ${this.max} باشد.`,
|
||||
text: `مقدار ${this.label} نمیتواند بیشتر از ${this.max} باشد.`,
|
||||
});
|
||||
}
|
||||
if (minValidator) {
|
||||
this.toastService.warn({
|
||||
text: `مقدار ${this.label} نمیتواند کمتر از ${this.min} باشد.`,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -233,8 +237,12 @@ export class InputComponent {
|
||||
}
|
||||
|
||||
if (replacedTargetValue !== null) {
|
||||
console.log(replacedTargetValue);
|
||||
|
||||
// @ts-ignore
|
||||
this.$event.value = replacedTargetValue;
|
||||
$event.value = replacedTargetValue;
|
||||
// @ts-ignore
|
||||
$event.target.value = replacedTargetValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
<input pInputText type="text" placeholder="جستجو..." (input)="onSearchInput($event.target.value)" />
|
||||
<input pInputText type="text" placeholder="جستجو..." class="w-full" (input)="onSearchInput($event.target.value)" />
|
||||
|
||||
Reference in New Issue
Block a user