@es.framework/ng.ui.theme 2.0.59 → 2.0.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -4,12 +4,12 @@ import { Subject, Observable, lastValueFrom, BehaviorSubject, map, filter } from
|
|
|
4
4
|
import * as i3$3 from '@es.framework/ng.core/services';
|
|
5
5
|
import { ConfigStateService, SessionStateService, LocalizationService, LocalStorageService, NavItemsService, UserMenuService, RoutesService, SubscriptionService, ReplaceableComponentsService } from '@es.framework/ng.core/services';
|
|
6
6
|
import { eLayoutType } from '@es.framework/ng.core/models';
|
|
7
|
-
import * as i2$
|
|
7
|
+
import * as i2$1 from '@angular/router';
|
|
8
8
|
import { Router, RouterModule, RouterOutlet, NavigationEnd } from '@angular/router';
|
|
9
9
|
import * as i1$1 from '@angular/common';
|
|
10
10
|
import { isPlatformBrowser, CommonModule } from '@angular/common';
|
|
11
11
|
import { StyleClassModule } from 'primeng/styleclass';
|
|
12
|
-
import * as i3$
|
|
12
|
+
import * as i3$2 from 'primeng/avatar';
|
|
13
13
|
import { AvatarModule } from 'primeng/avatar';
|
|
14
14
|
import * as i5 from 'primeng/menu';
|
|
15
15
|
import { MenuModule } from 'primeng/menu';
|
|
@@ -19,7 +19,7 @@ import { OverlayModule } from 'primeng/overlay';
|
|
|
19
19
|
import { VisibleDirective, HasPermissionDirective, ReplaceableTemplateDirective } from '@es.framework/ng.core/directives';
|
|
20
20
|
import { TranslatePipe, ToInjectorPipe } from '@es.framework/ng.core/pipes';
|
|
21
21
|
import { toSignal } from '@angular/core/rxjs-interop';
|
|
22
|
-
import * as
|
|
22
|
+
import * as i3 from '@angular/forms';
|
|
23
23
|
import { FormsModule } from '@angular/forms';
|
|
24
24
|
import { SelectModule } from 'primeng/select';
|
|
25
25
|
import * as i1 from 'primeng/popover';
|
|
@@ -30,11 +30,11 @@ import Aura from '@primeng/themes/aura';
|
|
|
30
30
|
import Lara from '@primeng/themes/lara';
|
|
31
31
|
import Nora from '@primeng/themes/nora';
|
|
32
32
|
import { PrimeNG } from 'primeng/config';
|
|
33
|
-
import * as i3 from 'primeng/selectbutton';
|
|
33
|
+
import * as i3$1 from 'primeng/selectbutton';
|
|
34
34
|
import { SelectButtonModule } from 'primeng/selectbutton';
|
|
35
35
|
import { AuthService } from '@es.framework/ng.core/abstracts';
|
|
36
36
|
import * as i4 from 'primeng/api';
|
|
37
|
-
import * as
|
|
37
|
+
import * as i4$1 from 'primeng/tooltip';
|
|
38
38
|
import { TooltipModule } from 'primeng/tooltip';
|
|
39
39
|
import Swal from 'sweetalert2';
|
|
40
40
|
import { NAVIGATE_TO_MANAGE_PROFILE } from '@es.framework/ng.core/tokens';
|
|
@@ -210,36 +210,36 @@ class LanguagesComponent {
|
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: LanguagesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
213
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: LanguagesComponent, isStandalone: true, selector: "abp-languages", ngImport: i0, template: `
|
|
214
|
-
@if (languages(); as langs) {
|
|
215
|
-
<div>
|
|
216
|
-
<!-- -->
|
|
217
|
-
<button
|
|
218
|
-
pButton
|
|
219
|
-
type="button"
|
|
220
|
-
icon="pi pi-globe"
|
|
221
|
-
class="p-button-text"
|
|
222
|
-
[title]="'اختر اللغة'"
|
|
223
|
-
(click)="overlay.toggle($event)"
|
|
224
|
-
></button>
|
|
225
|
-
<p-popover #overlay >
|
|
226
|
-
<ul class="w-48">
|
|
227
|
-
@for (lang of langs; track lang) {
|
|
228
|
-
<li
|
|
229
|
-
class="flex items-center justify-between px-3 py-2 cursor-pointer hover:bg-gray-100"
|
|
230
|
-
(click)="onSelectLanguage(lang.cultureName ?? ''); overlay.hide()"
|
|
231
|
-
>
|
|
232
|
-
<span>{{ lang.displayName }}</span>
|
|
233
|
-
@if (lang.cultureName === selectedLang()) {
|
|
234
|
-
<i class="pi pi-check text-green-500"></i>
|
|
235
|
-
}
|
|
236
|
-
</li>
|
|
237
|
-
}
|
|
238
|
-
</ul>
|
|
239
|
-
</p-popover>
|
|
240
|
-
</div>
|
|
241
|
-
}
|
|
242
|
-
|
|
213
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: LanguagesComponent, isStandalone: true, selector: "abp-languages", ngImport: i0, template: `
|
|
214
|
+
@if (languages(); as langs) {
|
|
215
|
+
<div>
|
|
216
|
+
<!-- -->
|
|
217
|
+
<button
|
|
218
|
+
pButton
|
|
219
|
+
type="button"
|
|
220
|
+
icon="pi pi-globe"
|
|
221
|
+
class="p-button-text"
|
|
222
|
+
[title]="'اختر اللغة'"
|
|
223
|
+
(click)="overlay.toggle($event)"
|
|
224
|
+
></button>
|
|
225
|
+
<p-popover #overlay >
|
|
226
|
+
<ul class="w-48">
|
|
227
|
+
@for (lang of langs; track lang) {
|
|
228
|
+
<li
|
|
229
|
+
class="flex items-center justify-between px-3 py-2 cursor-pointer hover:bg-gray-100"
|
|
230
|
+
(click)="onSelectLanguage(lang.cultureName ?? ''); overlay.hide()"
|
|
231
|
+
>
|
|
232
|
+
<span>{{ lang.displayName }}</span>
|
|
233
|
+
@if (lang.cultureName === selectedLang()) {
|
|
234
|
+
<i class="pi pi-check text-green-500"></i>
|
|
235
|
+
}
|
|
236
|
+
</li>
|
|
237
|
+
}
|
|
238
|
+
</ul>
|
|
239
|
+
</p-popover>
|
|
240
|
+
</div>
|
|
241
|
+
}
|
|
242
|
+
|
|
243
243
|
`, isInline: true, dependencies: [{ kind: "ngmodule", type: SelectModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i1.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i2.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }] });
|
|
244
244
|
}
|
|
245
245
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: LanguagesComponent, decorators: [{
|
|
@@ -248,36 +248,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
248
248
|
selector: 'abp-languages',
|
|
249
249
|
standalone: true,
|
|
250
250
|
imports: [SelectModule, FormsModule, PopoverModule, ButtonModule],
|
|
251
|
-
template: `
|
|
252
|
-
@if (languages(); as langs) {
|
|
253
|
-
<div>
|
|
254
|
-
<!-- -->
|
|
255
|
-
<button
|
|
256
|
-
pButton
|
|
257
|
-
type="button"
|
|
258
|
-
icon="pi pi-globe"
|
|
259
|
-
class="p-button-text"
|
|
260
|
-
[title]="'اختر اللغة'"
|
|
261
|
-
(click)="overlay.toggle($event)"
|
|
262
|
-
></button>
|
|
263
|
-
<p-popover #overlay >
|
|
264
|
-
<ul class="w-48">
|
|
265
|
-
@for (lang of langs; track lang) {
|
|
266
|
-
<li
|
|
267
|
-
class="flex items-center justify-between px-3 py-2 cursor-pointer hover:bg-gray-100"
|
|
268
|
-
(click)="onSelectLanguage(lang.cultureName ?? ''); overlay.hide()"
|
|
269
|
-
>
|
|
270
|
-
<span>{{ lang.displayName }}</span>
|
|
271
|
-
@if (lang.cultureName === selectedLang()) {
|
|
272
|
-
<i class="pi pi-check text-green-500"></i>
|
|
273
|
-
}
|
|
274
|
-
</li>
|
|
275
|
-
}
|
|
276
|
-
</ul>
|
|
277
|
-
</p-popover>
|
|
278
|
-
</div>
|
|
279
|
-
}
|
|
280
|
-
|
|
251
|
+
template: `
|
|
252
|
+
@if (languages(); as langs) {
|
|
253
|
+
<div>
|
|
254
|
+
<!-- -->
|
|
255
|
+
<button
|
|
256
|
+
pButton
|
|
257
|
+
type="button"
|
|
258
|
+
icon="pi pi-globe"
|
|
259
|
+
class="p-button-text"
|
|
260
|
+
[title]="'اختر اللغة'"
|
|
261
|
+
(click)="overlay.toggle($event)"
|
|
262
|
+
></button>
|
|
263
|
+
<p-popover #overlay >
|
|
264
|
+
<ul class="w-48">
|
|
265
|
+
@for (lang of langs; track lang) {
|
|
266
|
+
<li
|
|
267
|
+
class="flex items-center justify-between px-3 py-2 cursor-pointer hover:bg-gray-100"
|
|
268
|
+
(click)="onSelectLanguage(lang.cultureName ?? ''); overlay.hide()"
|
|
269
|
+
>
|
|
270
|
+
<span>{{ lang.displayName }}</span>
|
|
271
|
+
@if (lang.cultureName === selectedLang()) {
|
|
272
|
+
<i class="pi pi-check text-green-500"></i>
|
|
273
|
+
}
|
|
274
|
+
</li>
|
|
275
|
+
}
|
|
276
|
+
</ul>
|
|
277
|
+
</p-popover>
|
|
278
|
+
</div>
|
|
279
|
+
}
|
|
280
|
+
|
|
281
281
|
`
|
|
282
282
|
}]
|
|
283
283
|
}], ctorParameters: () => [] });
|
|
@@ -452,7 +452,45 @@ class AppConfigurator {
|
|
|
452
452
|
primaryColors = computed(() => {
|
|
453
453
|
const presetPalette = presets[this.layoutService.layoutConfig().preset].primitive;
|
|
454
454
|
const colors = ['blue', 'green', 'lime', 'orange', 'amber', 'yellow', 'teal', 'cyan', 'sky', 'emerald', 'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose'];
|
|
455
|
-
const
|
|
455
|
+
const customColors = [
|
|
456
|
+
{
|
|
457
|
+
name: 'ghazali',
|
|
458
|
+
palette: {
|
|
459
|
+
50: '#fbf7f2',
|
|
460
|
+
100: '#f4eadf',
|
|
461
|
+
200: '#e8d3bf',
|
|
462
|
+
300: '#d8b596',
|
|
463
|
+
400: '#c99572',
|
|
464
|
+
500: '#b97855',
|
|
465
|
+
600: '#a45f3f',
|
|
466
|
+
700: '#884a34',
|
|
467
|
+
800: '#713d2f',
|
|
468
|
+
900: '#5e342b',
|
|
469
|
+
950: '#351914'
|
|
470
|
+
}
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
name: 'brown',
|
|
474
|
+
palette: {
|
|
475
|
+
50: '#faf6f3',
|
|
476
|
+
100: '#f1e5dc',
|
|
477
|
+
200: '#e2c9b8',
|
|
478
|
+
300: '#cea58a',
|
|
479
|
+
400: '#b97e5d',
|
|
480
|
+
500: '#9f6244',
|
|
481
|
+
600: '#814a34',
|
|
482
|
+
700: '#6a3d2e',
|
|
483
|
+
800: '#59342a',
|
|
484
|
+
900: '#4c2e27',
|
|
485
|
+
950: '#2b1712'
|
|
486
|
+
}
|
|
487
|
+
},
|
|
488
|
+
];
|
|
489
|
+
// const palettes: SurfacesType[] = [{ name: 'noir', palette: {} }];
|
|
490
|
+
const palettes = [
|
|
491
|
+
{ name: 'noir', palette: {} },
|
|
492
|
+
...customColors
|
|
493
|
+
];
|
|
456
494
|
colors.forEach((color) => {
|
|
457
495
|
palettes.push({
|
|
458
496
|
name: color,
|
|
@@ -636,54 +674,54 @@ class AppConfigurator {
|
|
|
636
674
|
this.layoutService.layoutConfig.update((prev) => ({ ...prev, menuMode: event }));
|
|
637
675
|
}
|
|
638
676
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AppConfigurator, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
639
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: AppConfigurator, isStandalone: true, selector: "app-configurator", ngImport: i0, template: `
|
|
640
|
-
<div class="flex flex-col gap-4">
|
|
641
|
-
<div>
|
|
642
|
-
<span class="text-sm text-muted-color font-semibold">Primary</span>
|
|
643
|
-
<div class="pt-2 flex gap-2 flex-wrap justify-start">
|
|
644
|
-
@for (primaryColor of primaryColors(); track primaryColor.name) {
|
|
645
|
-
<button
|
|
646
|
-
type="button"
|
|
647
|
-
[title]="primaryColor.name"
|
|
648
|
-
(click)="updateColors($event, 'primary', primaryColor)"
|
|
649
|
-
[ngClass]="{ 'outline-primary': primaryColor.name === selectedPrimaryColor() }"
|
|
650
|
-
class="border-none w-5 h-5 rounded-full p-0 cursor-pointer outline-none outline-offset-1"
|
|
651
|
-
[style]="{
|
|
652
|
-
'background-color': primaryColor?.name === 'noir' ? 'var(--text-color)' : primaryColor?.palette?.['500']
|
|
653
|
-
}"
|
|
654
|
-
></button>
|
|
655
|
-
}
|
|
656
|
-
</div>
|
|
657
|
-
</div>
|
|
658
|
-
<div>
|
|
659
|
-
<span class="text-sm text-muted-color font-semibold">Surface</span>
|
|
660
|
-
<div class="pt-2 flex gap-2 flex-wrap justify-start">
|
|
661
|
-
@for (surface of surfaces; track surface.name) {
|
|
662
|
-
<button
|
|
663
|
-
type="button"
|
|
664
|
-
[title]="surface.name"
|
|
665
|
-
(click)="updateColors($event, 'surface', surface)"
|
|
666
|
-
[ngClass]="{ 'outline-primary': selectedSurfaceColor() ? selectedSurfaceColor() === surface.name : layoutService.layoutConfig().darkTheme ? surface.name === 'zinc' : surface.name === 'slate' }"
|
|
667
|
-
class="border-none w-5 h-5 rounded-full p-0 cursor-pointer outline-none outline-offset-1"
|
|
668
|
-
[style]="{
|
|
669
|
-
'background-color': surface?.name === 'noir' ? 'var(--text-color)' : surface?.palette?.['500']
|
|
670
|
-
}"
|
|
671
|
-
></button>
|
|
672
|
-
}
|
|
673
|
-
</div>
|
|
674
|
-
</div>
|
|
675
|
-
<div class="flex flex-col gap-2">
|
|
676
|
-
<span class="text-sm text-muted-color font-semibold">Presets</span>
|
|
677
|
-
<p-selectbutton [options]="presets" [ngModel]="selectedPreset()" (ngModelChange)="onPresetChange($event)" [allowEmpty]="false" size="small" />
|
|
678
|
-
</div>
|
|
679
|
-
@if (showMenuModeButton()) {
|
|
680
|
-
<div class="flex flex-col gap-2">
|
|
681
|
-
<span class="text-sm text-muted-color font-semibold">Menu Mode</span>
|
|
682
|
-
<p-selectbutton [ngModel]="menuMode()" (ngModelChange)="onMenuModeChange($event)" [options]="menuModeOptions" [allowEmpty]="false" size="small" />
|
|
683
|
-
</div>
|
|
684
|
-
}
|
|
685
|
-
</div>
|
|
686
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type:
|
|
677
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: AppConfigurator, isStandalone: true, selector: "app-configurator", ngImport: i0, template: `
|
|
678
|
+
<div class="flex flex-col gap-4">
|
|
679
|
+
<div>
|
|
680
|
+
<span class="text-sm text-muted-color font-semibold">Primary</span>
|
|
681
|
+
<div class="pt-2 flex gap-2 flex-wrap justify-start">
|
|
682
|
+
@for (primaryColor of primaryColors(); track primaryColor.name) {
|
|
683
|
+
<button
|
|
684
|
+
type="button"
|
|
685
|
+
[title]="primaryColor.name"
|
|
686
|
+
(click)="updateColors($event, 'primary', primaryColor)"
|
|
687
|
+
[ngClass]="{ 'outline-primary': primaryColor.name === selectedPrimaryColor() }"
|
|
688
|
+
class="border-none w-5 h-5 rounded-full p-0 cursor-pointer outline-none outline-offset-1"
|
|
689
|
+
[style]="{
|
|
690
|
+
'background-color': primaryColor?.name === 'noir' ? 'var(--text-color)' : primaryColor?.palette?.['500']
|
|
691
|
+
}"
|
|
692
|
+
></button>
|
|
693
|
+
}
|
|
694
|
+
</div>
|
|
695
|
+
</div>
|
|
696
|
+
<div>
|
|
697
|
+
<span class="text-sm text-muted-color font-semibold">Surface</span>
|
|
698
|
+
<div class="pt-2 flex gap-2 flex-wrap justify-start">
|
|
699
|
+
@for (surface of surfaces; track surface.name) {
|
|
700
|
+
<button
|
|
701
|
+
type="button"
|
|
702
|
+
[title]="surface.name"
|
|
703
|
+
(click)="updateColors($event, 'surface', surface)"
|
|
704
|
+
[ngClass]="{ 'outline-primary': selectedSurfaceColor() ? selectedSurfaceColor() === surface.name : layoutService.layoutConfig().darkTheme ? surface.name === 'zinc' : surface.name === 'slate' }"
|
|
705
|
+
class="border-none w-5 h-5 rounded-full p-0 cursor-pointer outline-none outline-offset-1"
|
|
706
|
+
[style]="{
|
|
707
|
+
'background-color': surface?.name === 'noir' ? 'var(--text-color)' : surface?.palette?.['500']
|
|
708
|
+
}"
|
|
709
|
+
></button>
|
|
710
|
+
}
|
|
711
|
+
</div>
|
|
712
|
+
</div>
|
|
713
|
+
<div class="flex flex-col gap-2">
|
|
714
|
+
<span class="text-sm text-muted-color font-semibold">Presets</span>
|
|
715
|
+
<p-selectbutton [options]="presets" [ngModel]="selectedPreset()" (ngModelChange)="onPresetChange($event)" [allowEmpty]="false" size="small" />
|
|
716
|
+
</div>
|
|
717
|
+
@if (showMenuModeButton()) {
|
|
718
|
+
<div class="flex flex-col gap-2">
|
|
719
|
+
<span class="text-sm text-muted-color font-semibold">Menu Mode</span>
|
|
720
|
+
<p-selectbutton [ngModel]="menuMode()" (ngModelChange)="onMenuModeChange($event)" [options]="menuModeOptions" [allowEmpty]="false" size="small" />
|
|
721
|
+
</div>
|
|
722
|
+
}
|
|
723
|
+
</div>
|
|
724
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: SelectButtonModule }, { kind: "component", type: i3$1.SelectButton, selector: "p-selectButton, p-selectbutton, p-select-button", inputs: ["options", "optionLabel", "optionValue", "optionDisabled", "unselectable", "tabindex", "multiple", "allowEmpty", "styleClass", "ariaLabelledBy", "dataKey", "autofocus", "size", "fluid"], outputs: ["onOptionClick", "onChange"] }] });
|
|
687
725
|
}
|
|
688
726
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AppConfigurator, decorators: [{
|
|
689
727
|
type: Component,
|
|
@@ -691,53 +729,53 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
691
729
|
selector: 'app-configurator',
|
|
692
730
|
standalone: true,
|
|
693
731
|
imports: [CommonModule, FormsModule, SelectButtonModule],
|
|
694
|
-
template: `
|
|
695
|
-
<div class="flex flex-col gap-4">
|
|
696
|
-
<div>
|
|
697
|
-
<span class="text-sm text-muted-color font-semibold">Primary</span>
|
|
698
|
-
<div class="pt-2 flex gap-2 flex-wrap justify-start">
|
|
699
|
-
@for (primaryColor of primaryColors(); track primaryColor.name) {
|
|
700
|
-
<button
|
|
701
|
-
type="button"
|
|
702
|
-
[title]="primaryColor.name"
|
|
703
|
-
(click)="updateColors($event, 'primary', primaryColor)"
|
|
704
|
-
[ngClass]="{ 'outline-primary': primaryColor.name === selectedPrimaryColor() }"
|
|
705
|
-
class="border-none w-5 h-5 rounded-full p-0 cursor-pointer outline-none outline-offset-1"
|
|
706
|
-
[style]="{
|
|
707
|
-
'background-color': primaryColor?.name === 'noir' ? 'var(--text-color)' : primaryColor?.palette?.['500']
|
|
708
|
-
}"
|
|
709
|
-
></button>
|
|
710
|
-
}
|
|
711
|
-
</div>
|
|
712
|
-
</div>
|
|
713
|
-
<div>
|
|
714
|
-
<span class="text-sm text-muted-color font-semibold">Surface</span>
|
|
715
|
-
<div class="pt-2 flex gap-2 flex-wrap justify-start">
|
|
716
|
-
@for (surface of surfaces; track surface.name) {
|
|
717
|
-
<button
|
|
718
|
-
type="button"
|
|
719
|
-
[title]="surface.name"
|
|
720
|
-
(click)="updateColors($event, 'surface', surface)"
|
|
721
|
-
[ngClass]="{ 'outline-primary': selectedSurfaceColor() ? selectedSurfaceColor() === surface.name : layoutService.layoutConfig().darkTheme ? surface.name === 'zinc' : surface.name === 'slate' }"
|
|
722
|
-
class="border-none w-5 h-5 rounded-full p-0 cursor-pointer outline-none outline-offset-1"
|
|
723
|
-
[style]="{
|
|
724
|
-
'background-color': surface?.name === 'noir' ? 'var(--text-color)' : surface?.palette?.['500']
|
|
725
|
-
}"
|
|
726
|
-
></button>
|
|
727
|
-
}
|
|
728
|
-
</div>
|
|
729
|
-
</div>
|
|
730
|
-
<div class="flex flex-col gap-2">
|
|
731
|
-
<span class="text-sm text-muted-color font-semibold">Presets</span>
|
|
732
|
-
<p-selectbutton [options]="presets" [ngModel]="selectedPreset()" (ngModelChange)="onPresetChange($event)" [allowEmpty]="false" size="small" />
|
|
733
|
-
</div>
|
|
734
|
-
@if (showMenuModeButton()) {
|
|
735
|
-
<div class="flex flex-col gap-2">
|
|
736
|
-
<span class="text-sm text-muted-color font-semibold">Menu Mode</span>
|
|
737
|
-
<p-selectbutton [ngModel]="menuMode()" (ngModelChange)="onMenuModeChange($event)" [options]="menuModeOptions" [allowEmpty]="false" size="small" />
|
|
738
|
-
</div>
|
|
739
|
-
}
|
|
740
|
-
</div>
|
|
732
|
+
template: `
|
|
733
|
+
<div class="flex flex-col gap-4">
|
|
734
|
+
<div>
|
|
735
|
+
<span class="text-sm text-muted-color font-semibold">Primary</span>
|
|
736
|
+
<div class="pt-2 flex gap-2 flex-wrap justify-start">
|
|
737
|
+
@for (primaryColor of primaryColors(); track primaryColor.name) {
|
|
738
|
+
<button
|
|
739
|
+
type="button"
|
|
740
|
+
[title]="primaryColor.name"
|
|
741
|
+
(click)="updateColors($event, 'primary', primaryColor)"
|
|
742
|
+
[ngClass]="{ 'outline-primary': primaryColor.name === selectedPrimaryColor() }"
|
|
743
|
+
class="border-none w-5 h-5 rounded-full p-0 cursor-pointer outline-none outline-offset-1"
|
|
744
|
+
[style]="{
|
|
745
|
+
'background-color': primaryColor?.name === 'noir' ? 'var(--text-color)' : primaryColor?.palette?.['500']
|
|
746
|
+
}"
|
|
747
|
+
></button>
|
|
748
|
+
}
|
|
749
|
+
</div>
|
|
750
|
+
</div>
|
|
751
|
+
<div>
|
|
752
|
+
<span class="text-sm text-muted-color font-semibold">Surface</span>
|
|
753
|
+
<div class="pt-2 flex gap-2 flex-wrap justify-start">
|
|
754
|
+
@for (surface of surfaces; track surface.name) {
|
|
755
|
+
<button
|
|
756
|
+
type="button"
|
|
757
|
+
[title]="surface.name"
|
|
758
|
+
(click)="updateColors($event, 'surface', surface)"
|
|
759
|
+
[ngClass]="{ 'outline-primary': selectedSurfaceColor() ? selectedSurfaceColor() === surface.name : layoutService.layoutConfig().darkTheme ? surface.name === 'zinc' : surface.name === 'slate' }"
|
|
760
|
+
class="border-none w-5 h-5 rounded-full p-0 cursor-pointer outline-none outline-offset-1"
|
|
761
|
+
[style]="{
|
|
762
|
+
'background-color': surface?.name === 'noir' ? 'var(--text-color)' : surface?.palette?.['500']
|
|
763
|
+
}"
|
|
764
|
+
></button>
|
|
765
|
+
}
|
|
766
|
+
</div>
|
|
767
|
+
</div>
|
|
768
|
+
<div class="flex flex-col gap-2">
|
|
769
|
+
<span class="text-sm text-muted-color font-semibold">Presets</span>
|
|
770
|
+
<p-selectbutton [options]="presets" [ngModel]="selectedPreset()" (ngModelChange)="onPresetChange($event)" [allowEmpty]="false" size="small" />
|
|
771
|
+
</div>
|
|
772
|
+
@if (showMenuModeButton()) {
|
|
773
|
+
<div class="flex flex-col gap-2">
|
|
774
|
+
<span class="text-sm text-muted-color font-semibold">Menu Mode</span>
|
|
775
|
+
<p-selectbutton [ngModel]="menuMode()" (ngModelChange)="onMenuModeChange($event)" [options]="menuModeOptions" [allowEmpty]="false" size="small" />
|
|
776
|
+
</div>
|
|
777
|
+
}
|
|
778
|
+
</div>
|
|
741
779
|
`,
|
|
742
780
|
}]
|
|
743
781
|
}] });
|
|
@@ -868,168 +906,168 @@ class NavItemsComponent {
|
|
|
868
906
|
this.authService.navigateToLogin();
|
|
869
907
|
}
|
|
870
908
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: NavItemsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
871
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: NavItemsComponent, isStandalone: true, selector: "app-nav-items", ngImport: i0, template: `
|
|
872
|
-
<header class="flex items-center justify-between px-6 h-16 bg-white shadow sticky top-0 z-9">
|
|
873
|
-
<!-- Left: Logo / Title -->
|
|
874
|
-
<div class="flex items-center space-x-3 rtl:space-x-reverse">
|
|
875
|
-
<img src="assets/logo.png" alt="Logo" class="h-8 w-8" />
|
|
876
|
-
<span class="text-lg font-semibold text-gray-800">{{ '' | translate }}</span>
|
|
877
|
-
</div>
|
|
878
|
-
|
|
879
|
-
<!-- Center: Nav Items -->
|
|
880
|
-
<div class="flex items-center space-x-4 rtl:space-x-reverse">
|
|
881
|
-
<ul class="flex space-x-4">
|
|
882
|
-
@for (item of navItems.items$ | async; track item.id) {
|
|
883
|
-
@if (!item.visible || item.visible(item)) {
|
|
884
|
-
<ng-container *frameworkVisible="!item.visible || item.visible(item)">
|
|
885
|
-
<li class="flex items-center">
|
|
886
|
-
@if (item.component) {
|
|
887
|
-
<ng-container
|
|
888
|
-
[ngComponentOutlet]="item.component"
|
|
889
|
-
[ngComponentOutletInjector]="item | toInjector"
|
|
890
|
-
></ng-container>
|
|
891
|
-
} @else {
|
|
892
|
-
<button
|
|
893
|
-
pButton
|
|
894
|
-
type="button"
|
|
895
|
-
class="p-button-text hover:bg-gray-100 focus:outline-none flex items-center"
|
|
896
|
-
(click)="item.action?.()"
|
|
897
|
-
>
|
|
898
|
-
<span [innerHTML]="item.html"></span>
|
|
899
|
-
</button>
|
|
900
|
-
}
|
|
901
|
-
</li>
|
|
902
|
-
</ng-container>
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
</ul>
|
|
906
|
-
</div>
|
|
907
|
-
|
|
908
|
-
<!-- Right: Actions -->
|
|
909
|
-
<div class="flex items-center rtl:space-x-reverse">
|
|
910
|
-
<!-- Configurator -->
|
|
911
|
-
|
|
912
|
-
<div>
|
|
913
|
-
<!-- -->
|
|
914
|
-
<button
|
|
915
|
-
pButton
|
|
916
|
-
type="button"
|
|
917
|
-
icon="pi pi-palette"
|
|
918
|
-
class="p-button-text"
|
|
919
|
-
[title]="''"
|
|
920
|
-
(click)="overlay.toggle($event)"
|
|
921
|
-
>
|
|
922
|
-
</button>
|
|
923
|
-
|
|
924
|
-
<p-popover #overlay >
|
|
925
|
-
<app-configurator />
|
|
926
|
-
</p-popover>
|
|
927
|
-
</div>
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
<!-- Dark Mode Toggle -->
|
|
931
|
-
<button
|
|
932
|
-
pButton
|
|
933
|
-
type="button"
|
|
934
|
-
[icon]="layoutService.isDarkTheme() ?'pi pi-moon': 'pi pi-sun'"
|
|
935
|
-
class="p-button-text"
|
|
936
|
-
(click)="toggleDarkMode()">
|
|
937
|
-
</button>
|
|
938
|
-
|
|
939
|
-
<!-- Language Switcher -->
|
|
940
|
-
<abp-languages></abp-languages>
|
|
941
|
-
|
|
942
|
-
<!-- User Menu -->
|
|
943
|
-
<div class="relative">
|
|
944
|
-
<button
|
|
945
|
-
class="p-link p-2"
|
|
946
|
-
(click)="menu.toggle($event)"
|
|
947
|
-
aria-label="User menu"
|
|
948
|
-
>
|
|
949
|
-
<p-avatar
|
|
950
|
-
[label]="loading ? '' : userName"
|
|
951
|
-
[icon]="loading ? 'pi pi-spinner' : ''"
|
|
952
|
-
[class]="{'pi-spin': loading}"
|
|
953
|
-
shape="circle"
|
|
954
|
-
class="bg-blue-600 text-white cursor-pointer"
|
|
955
|
-
[title]="(currentUser$ | async)?.name || ''"
|
|
956
|
-
></p-avatar>
|
|
957
|
-
</button>
|
|
958
|
-
|
|
959
|
-
<p-menu
|
|
960
|
-
#menu
|
|
961
|
-
[model]="userMenuItems"
|
|
962
|
-
[popup]="true"
|
|
963
|
-
[appendTo]="'body'"
|
|
964
|
-
styleClass="w-64 sm:w-72 shadow-lg rounded-md"
|
|
965
|
-
>
|
|
966
|
-
<ng-template pTemplate="start">
|
|
967
|
-
<div class="px-5 py-4 border-b border-gray-200 bg-gray-50 flex flex-col items-center text-center">
|
|
968
|
-
<p-avatar
|
|
969
|
-
[label]="userName"
|
|
970
|
-
shape="circle"
|
|
971
|
-
size="xlarge"
|
|
972
|
-
styleClass="bg-blue-600 text-white mb-3 shadow-lg"
|
|
973
|
-
[title]="(currentUser$ | async)?.name || ''"
|
|
974
|
-
></p-avatar>
|
|
975
|
-
<h5 class="text-xl font-semibold text-gray-800 leading-tight">
|
|
976
|
-
{{ (currentUser$ | async)?.name || 'اسم المستخدم' }}
|
|
977
|
-
</h5>
|
|
978
|
-
<p class="text-sm text-gray-600 truncate max-w-full">
|
|
979
|
-
{{ (currentUser$ | async)?.email || 'لا يوجد بريد إلكتروني' }}
|
|
980
|
-
</p>
|
|
981
|
-
@if ((selectedTenant$ | async); as tenant) {
|
|
982
|
-
<span
|
|
983
|
-
class="inline-block mt-2 px-3 py-1 text-xs rounded-full font-semibold"
|
|
984
|
-
[ngClass]="{
|
|
985
|
-
'bg-green-100 text-green-800': true
|
|
986
|
-
}"
|
|
987
|
-
>
|
|
988
|
-
{{ tenant?.name || '_' }}
|
|
989
|
-
</span>
|
|
990
|
-
}
|
|
991
|
-
</div>
|
|
992
|
-
</ng-template>
|
|
993
|
-
|
|
994
|
-
<ng-template pTemplate="item" let-item>
|
|
995
|
-
<!-- *frameworkVisible="!item.visible || item.visible(item)" -->
|
|
996
|
-
<ng-container >
|
|
997
|
-
<!-- *hasPermission="item.requiredPolicy" -->
|
|
998
|
-
<a
|
|
999
|
-
|
|
1000
|
-
class="p-menuitem-link flex items-center space-x-3 rtl:space-x-reverse px-5 py-2 hover:bg-gray-100 rounded-md"
|
|
1001
|
-
[ngClass]="item.styleClass || ''"
|
|
1002
|
-
(click)="item.command ? item.command() : null"
|
|
1003
|
-
[routerLink]="item.routerLink ? item.routerLink : null"
|
|
1004
|
-
tabindex="0"
|
|
1005
|
-
>
|
|
1006
|
-
@if (item.component) {
|
|
1007
|
-
<ng-container
|
|
1008
|
-
[ngComponentOutlet]="item.component"
|
|
1009
|
-
[ngComponentOutletInjector]="item | toInjector"
|
|
1010
|
-
></ng-container>
|
|
1011
|
-
} @else {
|
|
1012
|
-
<i [class]="item.icon + ' text-lg text-gray-600'"></i>
|
|
1013
|
-
<span class="text-gray-700">{{ item.label | translate }}</span>
|
|
1014
|
-
}
|
|
1015
|
-
</a>
|
|
1016
|
-
</ng-container>
|
|
1017
|
-
</ng-template>
|
|
1018
|
-
</p-menu>
|
|
1019
|
-
</div>
|
|
1020
|
-
|
|
1021
|
-
<!-- Logout Button (separate from menu) -->
|
|
1022
|
-
<!-- <button
|
|
1023
|
-
type="button"
|
|
1024
|
-
class="layout-topbar-action"
|
|
1025
|
-
(click)="logout()"
|
|
1026
|
-
title="تسجيل الخروج"
|
|
1027
|
-
>
|
|
1028
|
-
<i class="pi pi-sign-out"></i>
|
|
1029
|
-
</button> -->
|
|
1030
|
-
</div>
|
|
1031
|
-
</header>
|
|
1032
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2$
|
|
909
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: NavItemsComponent, isStandalone: true, selector: "app-nav-items", ngImport: i0, template: `
|
|
910
|
+
<header class="flex items-center justify-between px-6 h-16 bg-white shadow sticky top-0 z-9">
|
|
911
|
+
<!-- Left: Logo / Title -->
|
|
912
|
+
<div class="flex items-center space-x-3 rtl:space-x-reverse">
|
|
913
|
+
<img src="assets/logo.png" alt="Logo" class="h-8 w-8" />
|
|
914
|
+
<span class="text-lg font-semibold text-gray-800">{{ '' | translate }}</span>
|
|
915
|
+
</div>
|
|
916
|
+
|
|
917
|
+
<!-- Center: Nav Items -->
|
|
918
|
+
<div class="flex items-center space-x-4 rtl:space-x-reverse">
|
|
919
|
+
<ul class="flex space-x-4">
|
|
920
|
+
@for (item of navItems.items$ | async; track item.id) {
|
|
921
|
+
@if (!item.visible || item.visible(item)) {
|
|
922
|
+
<ng-container *frameworkVisible="!item.visible || item.visible(item)">
|
|
923
|
+
<li class="flex items-center">
|
|
924
|
+
@if (item.component) {
|
|
925
|
+
<ng-container
|
|
926
|
+
[ngComponentOutlet]="item.component"
|
|
927
|
+
[ngComponentOutletInjector]="item | toInjector"
|
|
928
|
+
></ng-container>
|
|
929
|
+
} @else {
|
|
930
|
+
<button
|
|
931
|
+
pButton
|
|
932
|
+
type="button"
|
|
933
|
+
class="p-button-text hover:bg-gray-100 focus:outline-none flex items-center"
|
|
934
|
+
(click)="item.action?.()"
|
|
935
|
+
>
|
|
936
|
+
<span [innerHTML]="item.html"></span>
|
|
937
|
+
</button>
|
|
938
|
+
}
|
|
939
|
+
</li>
|
|
940
|
+
</ng-container>
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
</ul>
|
|
944
|
+
</div>
|
|
945
|
+
|
|
946
|
+
<!-- Right: Actions -->
|
|
947
|
+
<div class="flex items-center rtl:space-x-reverse">
|
|
948
|
+
<!-- Configurator -->
|
|
949
|
+
|
|
950
|
+
<div>
|
|
951
|
+
<!-- -->
|
|
952
|
+
<button
|
|
953
|
+
pButton
|
|
954
|
+
type="button"
|
|
955
|
+
icon="pi pi-palette"
|
|
956
|
+
class="p-button-text"
|
|
957
|
+
[title]="''"
|
|
958
|
+
(click)="overlay.toggle($event)"
|
|
959
|
+
>
|
|
960
|
+
</button>
|
|
961
|
+
|
|
962
|
+
<p-popover #overlay >
|
|
963
|
+
<app-configurator />
|
|
964
|
+
</p-popover>
|
|
965
|
+
</div>
|
|
966
|
+
|
|
967
|
+
|
|
968
|
+
<!-- Dark Mode Toggle -->
|
|
969
|
+
<button
|
|
970
|
+
pButton
|
|
971
|
+
type="button"
|
|
972
|
+
[icon]="layoutService.isDarkTheme() ?'pi pi-moon': 'pi pi-sun'"
|
|
973
|
+
class="p-button-text"
|
|
974
|
+
(click)="toggleDarkMode()">
|
|
975
|
+
</button>
|
|
976
|
+
|
|
977
|
+
<!-- Language Switcher -->
|
|
978
|
+
<abp-languages></abp-languages>
|
|
979
|
+
|
|
980
|
+
<!-- User Menu -->
|
|
981
|
+
<div class="relative">
|
|
982
|
+
<button
|
|
983
|
+
class="p-link p-2"
|
|
984
|
+
(click)="menu.toggle($event)"
|
|
985
|
+
aria-label="User menu"
|
|
986
|
+
>
|
|
987
|
+
<p-avatar
|
|
988
|
+
[label]="loading ? '' : userName"
|
|
989
|
+
[icon]="loading ? 'pi pi-spinner' : ''"
|
|
990
|
+
[class]="{'pi-spin': loading}"
|
|
991
|
+
shape="circle"
|
|
992
|
+
class="bg-blue-600 text-white cursor-pointer"
|
|
993
|
+
[title]="(currentUser$ | async)?.name || ''"
|
|
994
|
+
></p-avatar>
|
|
995
|
+
</button>
|
|
996
|
+
|
|
997
|
+
<p-menu
|
|
998
|
+
#menu
|
|
999
|
+
[model]="userMenuItems"
|
|
1000
|
+
[popup]="true"
|
|
1001
|
+
[appendTo]="'body'"
|
|
1002
|
+
styleClass="w-64 sm:w-72 shadow-lg rounded-md"
|
|
1003
|
+
>
|
|
1004
|
+
<ng-template pTemplate="start">
|
|
1005
|
+
<div class="px-5 py-4 border-b border-gray-200 bg-gray-50 flex flex-col items-center text-center">
|
|
1006
|
+
<p-avatar
|
|
1007
|
+
[label]="userName"
|
|
1008
|
+
shape="circle"
|
|
1009
|
+
size="xlarge"
|
|
1010
|
+
styleClass="bg-blue-600 text-white mb-3 shadow-lg"
|
|
1011
|
+
[title]="(currentUser$ | async)?.name || ''"
|
|
1012
|
+
></p-avatar>
|
|
1013
|
+
<h5 class="text-xl font-semibold text-gray-800 leading-tight">
|
|
1014
|
+
{{ (currentUser$ | async)?.name || 'اسم المستخدم' }}
|
|
1015
|
+
</h5>
|
|
1016
|
+
<p class="text-sm text-gray-600 truncate max-w-full">
|
|
1017
|
+
{{ (currentUser$ | async)?.email || 'لا يوجد بريد إلكتروني' }}
|
|
1018
|
+
</p>
|
|
1019
|
+
@if ((selectedTenant$ | async); as tenant) {
|
|
1020
|
+
<span
|
|
1021
|
+
class="inline-block mt-2 px-3 py-1 text-xs rounded-full font-semibold"
|
|
1022
|
+
[ngClass]="{
|
|
1023
|
+
'bg-green-100 text-green-800': true
|
|
1024
|
+
}"
|
|
1025
|
+
>
|
|
1026
|
+
{{ tenant?.name || '_' }}
|
|
1027
|
+
</span>
|
|
1028
|
+
}
|
|
1029
|
+
</div>
|
|
1030
|
+
</ng-template>
|
|
1031
|
+
|
|
1032
|
+
<ng-template pTemplate="item" let-item>
|
|
1033
|
+
<!-- *frameworkVisible="!item.visible || item.visible(item)" -->
|
|
1034
|
+
<ng-container >
|
|
1035
|
+
<!-- *hasPermission="item.requiredPolicy" -->
|
|
1036
|
+
<a
|
|
1037
|
+
|
|
1038
|
+
class="p-menuitem-link flex items-center space-x-3 rtl:space-x-reverse px-5 py-2 hover:bg-gray-100 rounded-md"
|
|
1039
|
+
[ngClass]="item.styleClass || ''"
|
|
1040
|
+
(click)="item.command ? item.command() : null"
|
|
1041
|
+
[routerLink]="item.routerLink ? item.routerLink : null"
|
|
1042
|
+
tabindex="0"
|
|
1043
|
+
>
|
|
1044
|
+
@if (item.component) {
|
|
1045
|
+
<ng-container
|
|
1046
|
+
[ngComponentOutlet]="item.component"
|
|
1047
|
+
[ngComponentOutletInjector]="item | toInjector"
|
|
1048
|
+
></ng-container>
|
|
1049
|
+
} @else {
|
|
1050
|
+
<i [class]="item.icon + ' text-lg text-gray-600'"></i>
|
|
1051
|
+
<span class="text-gray-700">{{ item.label | translate }}</span>
|
|
1052
|
+
}
|
|
1053
|
+
</a>
|
|
1054
|
+
</ng-container>
|
|
1055
|
+
</ng-template>
|
|
1056
|
+
</p-menu>
|
|
1057
|
+
</div>
|
|
1058
|
+
|
|
1059
|
+
<!-- Logout Button (separate from menu) -->
|
|
1060
|
+
<!-- <button
|
|
1061
|
+
type="button"
|
|
1062
|
+
class="layout-topbar-action"
|
|
1063
|
+
(click)="logout()"
|
|
1064
|
+
title="تسجيل الخروج"
|
|
1065
|
+
>
|
|
1066
|
+
<i class="pi pi-sign-out"></i>
|
|
1067
|
+
</button> -->
|
|
1068
|
+
</div>
|
|
1069
|
+
</header>
|
|
1070
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: StyleClassModule }, { kind: "component", type: AppConfigurator, selector: "app-configurator" }, { kind: "component", type: LanguagesComponent, selector: "abp-languages" }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i3$2.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "directive", type: i4.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: MenuModule }, { kind: "component", type: i5.Menu, selector: "p-menu", inputs: ["model", "popup", "style", "styleClass", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "ariaLabel", "ariaLabelledBy", "id", "tabindex", "appendTo"], outputs: ["onShow", "onHide", "onBlur", "onFocus"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i2.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: VisibleDirective, selector: "[frameworkVisible]", inputs: ["frameworkVisible"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i1.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: ToInjectorPipe, name: "toInjector" }] });
|
|
1033
1071
|
}
|
|
1034
1072
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: NavItemsComponent, decorators: [{
|
|
1035
1073
|
type: Component,
|
|
@@ -1052,167 +1090,167 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
1052
1090
|
ToInjectorPipe,
|
|
1053
1091
|
PopoverModule
|
|
1054
1092
|
],
|
|
1055
|
-
template: `
|
|
1056
|
-
<header class="flex items-center justify-between px-6 h-16 bg-white shadow sticky top-0 z-9">
|
|
1057
|
-
<!-- Left: Logo / Title -->
|
|
1058
|
-
<div class="flex items-center space-x-3 rtl:space-x-reverse">
|
|
1059
|
-
<img src="assets/logo.png" alt="Logo" class="h-8 w-8" />
|
|
1060
|
-
<span class="text-lg font-semibold text-gray-800">{{ '' | translate }}</span>
|
|
1061
|
-
</div>
|
|
1062
|
-
|
|
1063
|
-
<!-- Center: Nav Items -->
|
|
1064
|
-
<div class="flex items-center space-x-4 rtl:space-x-reverse">
|
|
1065
|
-
<ul class="flex space-x-4">
|
|
1066
|
-
@for (item of navItems.items$ | async; track item.id) {
|
|
1067
|
-
@if (!item.visible || item.visible(item)) {
|
|
1068
|
-
<ng-container *frameworkVisible="!item.visible || item.visible(item)">
|
|
1069
|
-
<li class="flex items-center">
|
|
1070
|
-
@if (item.component) {
|
|
1071
|
-
<ng-container
|
|
1072
|
-
[ngComponentOutlet]="item.component"
|
|
1073
|
-
[ngComponentOutletInjector]="item | toInjector"
|
|
1074
|
-
></ng-container>
|
|
1075
|
-
} @else {
|
|
1076
|
-
<button
|
|
1077
|
-
pButton
|
|
1078
|
-
type="button"
|
|
1079
|
-
class="p-button-text hover:bg-gray-100 focus:outline-none flex items-center"
|
|
1080
|
-
(click)="item.action?.()"
|
|
1081
|
-
>
|
|
1082
|
-
<span [innerHTML]="item.html"></span>
|
|
1083
|
-
</button>
|
|
1084
|
-
}
|
|
1085
|
-
</li>
|
|
1086
|
-
</ng-container>
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
</ul>
|
|
1090
|
-
</div>
|
|
1091
|
-
|
|
1092
|
-
<!-- Right: Actions -->
|
|
1093
|
-
<div class="flex items-center rtl:space-x-reverse">
|
|
1094
|
-
<!-- Configurator -->
|
|
1095
|
-
|
|
1096
|
-
<div>
|
|
1097
|
-
<!-- -->
|
|
1098
|
-
<button
|
|
1099
|
-
pButton
|
|
1100
|
-
type="button"
|
|
1101
|
-
icon="pi pi-palette"
|
|
1102
|
-
class="p-button-text"
|
|
1103
|
-
[title]="''"
|
|
1104
|
-
(click)="overlay.toggle($event)"
|
|
1105
|
-
>
|
|
1106
|
-
</button>
|
|
1107
|
-
|
|
1108
|
-
<p-popover #overlay >
|
|
1109
|
-
<app-configurator />
|
|
1110
|
-
</p-popover>
|
|
1111
|
-
</div>
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
<!-- Dark Mode Toggle -->
|
|
1115
|
-
<button
|
|
1116
|
-
pButton
|
|
1117
|
-
type="button"
|
|
1118
|
-
[icon]="layoutService.isDarkTheme() ?'pi pi-moon': 'pi pi-sun'"
|
|
1119
|
-
class="p-button-text"
|
|
1120
|
-
(click)="toggleDarkMode()">
|
|
1121
|
-
</button>
|
|
1122
|
-
|
|
1123
|
-
<!-- Language Switcher -->
|
|
1124
|
-
<abp-languages></abp-languages>
|
|
1125
|
-
|
|
1126
|
-
<!-- User Menu -->
|
|
1127
|
-
<div class="relative">
|
|
1128
|
-
<button
|
|
1129
|
-
class="p-link p-2"
|
|
1130
|
-
(click)="menu.toggle($event)"
|
|
1131
|
-
aria-label="User menu"
|
|
1132
|
-
>
|
|
1133
|
-
<p-avatar
|
|
1134
|
-
[label]="loading ? '' : userName"
|
|
1135
|
-
[icon]="loading ? 'pi pi-spinner' : ''"
|
|
1136
|
-
[class]="{'pi-spin': loading}"
|
|
1137
|
-
shape="circle"
|
|
1138
|
-
class="bg-blue-600 text-white cursor-pointer"
|
|
1139
|
-
[title]="(currentUser$ | async)?.name || ''"
|
|
1140
|
-
></p-avatar>
|
|
1141
|
-
</button>
|
|
1142
|
-
|
|
1143
|
-
<p-menu
|
|
1144
|
-
#menu
|
|
1145
|
-
[model]="userMenuItems"
|
|
1146
|
-
[popup]="true"
|
|
1147
|
-
[appendTo]="'body'"
|
|
1148
|
-
styleClass="w-64 sm:w-72 shadow-lg rounded-md"
|
|
1149
|
-
>
|
|
1150
|
-
<ng-template pTemplate="start">
|
|
1151
|
-
<div class="px-5 py-4 border-b border-gray-200 bg-gray-50 flex flex-col items-center text-center">
|
|
1152
|
-
<p-avatar
|
|
1153
|
-
[label]="userName"
|
|
1154
|
-
shape="circle"
|
|
1155
|
-
size="xlarge"
|
|
1156
|
-
styleClass="bg-blue-600 text-white mb-3 shadow-lg"
|
|
1157
|
-
[title]="(currentUser$ | async)?.name || ''"
|
|
1158
|
-
></p-avatar>
|
|
1159
|
-
<h5 class="text-xl font-semibold text-gray-800 leading-tight">
|
|
1160
|
-
{{ (currentUser$ | async)?.name || 'اسم المستخدم' }}
|
|
1161
|
-
</h5>
|
|
1162
|
-
<p class="text-sm text-gray-600 truncate max-w-full">
|
|
1163
|
-
{{ (currentUser$ | async)?.email || 'لا يوجد بريد إلكتروني' }}
|
|
1164
|
-
</p>
|
|
1165
|
-
@if ((selectedTenant$ | async); as tenant) {
|
|
1166
|
-
<span
|
|
1167
|
-
class="inline-block mt-2 px-3 py-1 text-xs rounded-full font-semibold"
|
|
1168
|
-
[ngClass]="{
|
|
1169
|
-
'bg-green-100 text-green-800': true
|
|
1170
|
-
}"
|
|
1171
|
-
>
|
|
1172
|
-
{{ tenant?.name || '_' }}
|
|
1173
|
-
</span>
|
|
1174
|
-
}
|
|
1175
|
-
</div>
|
|
1176
|
-
</ng-template>
|
|
1177
|
-
|
|
1178
|
-
<ng-template pTemplate="item" let-item>
|
|
1179
|
-
<!-- *frameworkVisible="!item.visible || item.visible(item)" -->
|
|
1180
|
-
<ng-container >
|
|
1181
|
-
<!-- *hasPermission="item.requiredPolicy" -->
|
|
1182
|
-
<a
|
|
1183
|
-
|
|
1184
|
-
class="p-menuitem-link flex items-center space-x-3 rtl:space-x-reverse px-5 py-2 hover:bg-gray-100 rounded-md"
|
|
1185
|
-
[ngClass]="item.styleClass || ''"
|
|
1186
|
-
(click)="item.command ? item.command() : null"
|
|
1187
|
-
[routerLink]="item.routerLink ? item.routerLink : null"
|
|
1188
|
-
tabindex="0"
|
|
1189
|
-
>
|
|
1190
|
-
@if (item.component) {
|
|
1191
|
-
<ng-container
|
|
1192
|
-
[ngComponentOutlet]="item.component"
|
|
1193
|
-
[ngComponentOutletInjector]="item | toInjector"
|
|
1194
|
-
></ng-container>
|
|
1195
|
-
} @else {
|
|
1196
|
-
<i [class]="item.icon + ' text-lg text-gray-600'"></i>
|
|
1197
|
-
<span class="text-gray-700">{{ item.label | translate }}</span>
|
|
1198
|
-
}
|
|
1199
|
-
</a>
|
|
1200
|
-
</ng-container>
|
|
1201
|
-
</ng-template>
|
|
1202
|
-
</p-menu>
|
|
1203
|
-
</div>
|
|
1204
|
-
|
|
1205
|
-
<!-- Logout Button (separate from menu) -->
|
|
1206
|
-
<!-- <button
|
|
1207
|
-
type="button"
|
|
1208
|
-
class="layout-topbar-action"
|
|
1209
|
-
(click)="logout()"
|
|
1210
|
-
title="تسجيل الخروج"
|
|
1211
|
-
>
|
|
1212
|
-
<i class="pi pi-sign-out"></i>
|
|
1213
|
-
</button> -->
|
|
1214
|
-
</div>
|
|
1215
|
-
</header>
|
|
1093
|
+
template: `
|
|
1094
|
+
<header class="flex items-center justify-between px-6 h-16 bg-white shadow sticky top-0 z-9">
|
|
1095
|
+
<!-- Left: Logo / Title -->
|
|
1096
|
+
<div class="flex items-center space-x-3 rtl:space-x-reverse">
|
|
1097
|
+
<img src="assets/logo.png" alt="Logo" class="h-8 w-8" />
|
|
1098
|
+
<span class="text-lg font-semibold text-gray-800">{{ '' | translate }}</span>
|
|
1099
|
+
</div>
|
|
1100
|
+
|
|
1101
|
+
<!-- Center: Nav Items -->
|
|
1102
|
+
<div class="flex items-center space-x-4 rtl:space-x-reverse">
|
|
1103
|
+
<ul class="flex space-x-4">
|
|
1104
|
+
@for (item of navItems.items$ | async; track item.id) {
|
|
1105
|
+
@if (!item.visible || item.visible(item)) {
|
|
1106
|
+
<ng-container *frameworkVisible="!item.visible || item.visible(item)">
|
|
1107
|
+
<li class="flex items-center">
|
|
1108
|
+
@if (item.component) {
|
|
1109
|
+
<ng-container
|
|
1110
|
+
[ngComponentOutlet]="item.component"
|
|
1111
|
+
[ngComponentOutletInjector]="item | toInjector"
|
|
1112
|
+
></ng-container>
|
|
1113
|
+
} @else {
|
|
1114
|
+
<button
|
|
1115
|
+
pButton
|
|
1116
|
+
type="button"
|
|
1117
|
+
class="p-button-text hover:bg-gray-100 focus:outline-none flex items-center"
|
|
1118
|
+
(click)="item.action?.()"
|
|
1119
|
+
>
|
|
1120
|
+
<span [innerHTML]="item.html"></span>
|
|
1121
|
+
</button>
|
|
1122
|
+
}
|
|
1123
|
+
</li>
|
|
1124
|
+
</ng-container>
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
</ul>
|
|
1128
|
+
</div>
|
|
1129
|
+
|
|
1130
|
+
<!-- Right: Actions -->
|
|
1131
|
+
<div class="flex items-center rtl:space-x-reverse">
|
|
1132
|
+
<!-- Configurator -->
|
|
1133
|
+
|
|
1134
|
+
<div>
|
|
1135
|
+
<!-- -->
|
|
1136
|
+
<button
|
|
1137
|
+
pButton
|
|
1138
|
+
type="button"
|
|
1139
|
+
icon="pi pi-palette"
|
|
1140
|
+
class="p-button-text"
|
|
1141
|
+
[title]="''"
|
|
1142
|
+
(click)="overlay.toggle($event)"
|
|
1143
|
+
>
|
|
1144
|
+
</button>
|
|
1145
|
+
|
|
1146
|
+
<p-popover #overlay >
|
|
1147
|
+
<app-configurator />
|
|
1148
|
+
</p-popover>
|
|
1149
|
+
</div>
|
|
1150
|
+
|
|
1151
|
+
|
|
1152
|
+
<!-- Dark Mode Toggle -->
|
|
1153
|
+
<button
|
|
1154
|
+
pButton
|
|
1155
|
+
type="button"
|
|
1156
|
+
[icon]="layoutService.isDarkTheme() ?'pi pi-moon': 'pi pi-sun'"
|
|
1157
|
+
class="p-button-text"
|
|
1158
|
+
(click)="toggleDarkMode()">
|
|
1159
|
+
</button>
|
|
1160
|
+
|
|
1161
|
+
<!-- Language Switcher -->
|
|
1162
|
+
<abp-languages></abp-languages>
|
|
1163
|
+
|
|
1164
|
+
<!-- User Menu -->
|
|
1165
|
+
<div class="relative">
|
|
1166
|
+
<button
|
|
1167
|
+
class="p-link p-2"
|
|
1168
|
+
(click)="menu.toggle($event)"
|
|
1169
|
+
aria-label="User menu"
|
|
1170
|
+
>
|
|
1171
|
+
<p-avatar
|
|
1172
|
+
[label]="loading ? '' : userName"
|
|
1173
|
+
[icon]="loading ? 'pi pi-spinner' : ''"
|
|
1174
|
+
[class]="{'pi-spin': loading}"
|
|
1175
|
+
shape="circle"
|
|
1176
|
+
class="bg-blue-600 text-white cursor-pointer"
|
|
1177
|
+
[title]="(currentUser$ | async)?.name || ''"
|
|
1178
|
+
></p-avatar>
|
|
1179
|
+
</button>
|
|
1180
|
+
|
|
1181
|
+
<p-menu
|
|
1182
|
+
#menu
|
|
1183
|
+
[model]="userMenuItems"
|
|
1184
|
+
[popup]="true"
|
|
1185
|
+
[appendTo]="'body'"
|
|
1186
|
+
styleClass="w-64 sm:w-72 shadow-lg rounded-md"
|
|
1187
|
+
>
|
|
1188
|
+
<ng-template pTemplate="start">
|
|
1189
|
+
<div class="px-5 py-4 border-b border-gray-200 bg-gray-50 flex flex-col items-center text-center">
|
|
1190
|
+
<p-avatar
|
|
1191
|
+
[label]="userName"
|
|
1192
|
+
shape="circle"
|
|
1193
|
+
size="xlarge"
|
|
1194
|
+
styleClass="bg-blue-600 text-white mb-3 shadow-lg"
|
|
1195
|
+
[title]="(currentUser$ | async)?.name || ''"
|
|
1196
|
+
></p-avatar>
|
|
1197
|
+
<h5 class="text-xl font-semibold text-gray-800 leading-tight">
|
|
1198
|
+
{{ (currentUser$ | async)?.name || 'اسم المستخدم' }}
|
|
1199
|
+
</h5>
|
|
1200
|
+
<p class="text-sm text-gray-600 truncate max-w-full">
|
|
1201
|
+
{{ (currentUser$ | async)?.email || 'لا يوجد بريد إلكتروني' }}
|
|
1202
|
+
</p>
|
|
1203
|
+
@if ((selectedTenant$ | async); as tenant) {
|
|
1204
|
+
<span
|
|
1205
|
+
class="inline-block mt-2 px-3 py-1 text-xs rounded-full font-semibold"
|
|
1206
|
+
[ngClass]="{
|
|
1207
|
+
'bg-green-100 text-green-800': true
|
|
1208
|
+
}"
|
|
1209
|
+
>
|
|
1210
|
+
{{ tenant?.name || '_' }}
|
|
1211
|
+
</span>
|
|
1212
|
+
}
|
|
1213
|
+
</div>
|
|
1214
|
+
</ng-template>
|
|
1215
|
+
|
|
1216
|
+
<ng-template pTemplate="item" let-item>
|
|
1217
|
+
<!-- *frameworkVisible="!item.visible || item.visible(item)" -->
|
|
1218
|
+
<ng-container >
|
|
1219
|
+
<!-- *hasPermission="item.requiredPolicy" -->
|
|
1220
|
+
<a
|
|
1221
|
+
|
|
1222
|
+
class="p-menuitem-link flex items-center space-x-3 rtl:space-x-reverse px-5 py-2 hover:bg-gray-100 rounded-md"
|
|
1223
|
+
[ngClass]="item.styleClass || ''"
|
|
1224
|
+
(click)="item.command ? item.command() : null"
|
|
1225
|
+
[routerLink]="item.routerLink ? item.routerLink : null"
|
|
1226
|
+
tabindex="0"
|
|
1227
|
+
>
|
|
1228
|
+
@if (item.component) {
|
|
1229
|
+
<ng-container
|
|
1230
|
+
[ngComponentOutlet]="item.component"
|
|
1231
|
+
[ngComponentOutletInjector]="item | toInjector"
|
|
1232
|
+
></ng-container>
|
|
1233
|
+
} @else {
|
|
1234
|
+
<i [class]="item.icon + ' text-lg text-gray-600'"></i>
|
|
1235
|
+
<span class="text-gray-700">{{ item.label | translate }}</span>
|
|
1236
|
+
}
|
|
1237
|
+
</a>
|
|
1238
|
+
</ng-container>
|
|
1239
|
+
</ng-template>
|
|
1240
|
+
</p-menu>
|
|
1241
|
+
</div>
|
|
1242
|
+
|
|
1243
|
+
<!-- Logout Button (separate from menu) -->
|
|
1244
|
+
<!-- <button
|
|
1245
|
+
type="button"
|
|
1246
|
+
class="layout-topbar-action"
|
|
1247
|
+
(click)="logout()"
|
|
1248
|
+
title="تسجيل الخروج"
|
|
1249
|
+
>
|
|
1250
|
+
<i class="pi pi-sign-out"></i>
|
|
1251
|
+
</button> -->
|
|
1252
|
+
</div>
|
|
1253
|
+
</header>
|
|
1216
1254
|
`
|
|
1217
1255
|
}]
|
|
1218
1256
|
}], ctorParameters: () => [] });
|
|
@@ -1221,6 +1259,7 @@ class RoutesComponent {
|
|
|
1221
1259
|
subSidebarVisible = false;
|
|
1222
1260
|
sidebarVisible = true;
|
|
1223
1261
|
isMobile = false;
|
|
1262
|
+
searchText = ''; // ✅ البحث
|
|
1224
1263
|
router = inject(Router);
|
|
1225
1264
|
localization = inject(LocalizationService);
|
|
1226
1265
|
layoutService = inject(LayoutService);
|
|
@@ -1228,13 +1267,14 @@ class RoutesComponent {
|
|
|
1228
1267
|
configState = inject(ConfigStateService);
|
|
1229
1268
|
secondToLastLevel$;
|
|
1230
1269
|
_menuItemsSubject = new BehaviorSubject([]);
|
|
1231
|
-
// menuItems$!: Observable<MenuItem[]>;
|
|
1232
1270
|
menuItems$ = this._menuItemsSubject.asObservable();
|
|
1233
1271
|
constructor() {
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1272
|
+
this.routesService.visible$.pipe(map(routes => {
|
|
1273
|
+
const items = this.buildItems(routes);
|
|
1274
|
+
// ✅ فتح الشجرة كاملة عند الدخول للنظام
|
|
1275
|
+
// this.setExpandedRecursive(items, true);
|
|
1276
|
+
return items;
|
|
1277
|
+
})).subscribe(items => this._menuItemsSubject.next(items));
|
|
1238
1278
|
}
|
|
1239
1279
|
ngOnInit() {
|
|
1240
1280
|
this.checkViewport();
|
|
@@ -1242,25 +1282,87 @@ class RoutesComponent {
|
|
|
1242
1282
|
const result = [];
|
|
1243
1283
|
for (const item of items) {
|
|
1244
1284
|
if (item.items && item.items.length > 0) {
|
|
1245
|
-
// إضافة جميع الأبناء المباشرين (المستوى الثاني)
|
|
1246
1285
|
result.push(...item.items);
|
|
1247
1286
|
}
|
|
1248
1287
|
}
|
|
1249
1288
|
return result;
|
|
1250
1289
|
}));
|
|
1251
|
-
//
|
|
1252
|
-
|
|
1253
|
-
|
|
1290
|
+
// ✅ إظهار الشجرة الفرعية مفتوحة في الديسكتوب عند الدخول
|
|
1291
|
+
if (!this.isMobile) {
|
|
1292
|
+
this.sidebarVisible = true;
|
|
1293
|
+
this.subSidebarVisible = true;
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
setExpandedRecursive(items, expanded) {
|
|
1297
|
+
for (const item of items) {
|
|
1298
|
+
item.expanded = expanded;
|
|
1299
|
+
if (item.items?.length) {
|
|
1300
|
+
this.setExpandedRecursive(item.items, expanded);
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
expandAll() {
|
|
1305
|
+
const items = this._menuItemsSubject.value;
|
|
1306
|
+
this.setExpandedRecursive(items, true);
|
|
1307
|
+
this.subSidebarVisible = true;
|
|
1308
|
+
this._menuItemsSubject.next([...items]);
|
|
1309
|
+
}
|
|
1310
|
+
collapseAll() {
|
|
1311
|
+
const items = this._menuItemsSubject.value;
|
|
1312
|
+
this.setExpandedRecursive(items, false);
|
|
1313
|
+
this._menuItemsSubject.next([...items]);
|
|
1314
|
+
}
|
|
1315
|
+
onSearchChange() {
|
|
1316
|
+
const items = this._menuItemsSubject.value;
|
|
1317
|
+
if (!this.searchText.trim()) {
|
|
1318
|
+
// ✅ عند مسح البحث ترجع مغلقة مثل البداية
|
|
1319
|
+
this.setExpandedRecursive(items, false);
|
|
1320
|
+
this._menuItemsSubject.next([...items]);
|
|
1321
|
+
return;
|
|
1322
|
+
}
|
|
1323
|
+
// ✅ أثناء البحث يفتح فقط المسارات المطابقة
|
|
1324
|
+
this.expandMatchedParents(items, this.searchText);
|
|
1325
|
+
this._menuItemsSubject.next([...items]);
|
|
1326
|
+
}
|
|
1327
|
+
expandMatchedParents(items, keyword) {
|
|
1328
|
+
const term = keyword.trim().toLowerCase();
|
|
1329
|
+
let hasMatch = false;
|
|
1330
|
+
for (const item of items) {
|
|
1331
|
+
const label = String(item.label ?? '').toLowerCase();
|
|
1332
|
+
const title = String(item.title ?? '').toLowerCase();
|
|
1333
|
+
const selfMatch = label.includes(term) || title.includes(term);
|
|
1334
|
+
const childMatch = item.items?.length
|
|
1335
|
+
? this.expandMatchedParents(item.items, keyword)
|
|
1336
|
+
: false;
|
|
1337
|
+
item.expanded = !!childMatch || !!selfMatch;
|
|
1338
|
+
if (selfMatch || childMatch) {
|
|
1339
|
+
hasMatch = true;
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
return hasMatch;
|
|
1343
|
+
}
|
|
1344
|
+
isSearchMatch(item) {
|
|
1345
|
+
const term = this.searchText.trim().toLowerCase();
|
|
1346
|
+
if (!term)
|
|
1347
|
+
return false;
|
|
1348
|
+
const label = String(item.label ?? '').toLowerCase();
|
|
1349
|
+
const title = String(item.title ?? '').toLowerCase();
|
|
1350
|
+
return label.includes(term) || title.includes(term);
|
|
1351
|
+
}
|
|
1352
|
+
clearSearch() {
|
|
1353
|
+
this.searchText = '';
|
|
1354
|
+
const items = this._menuItemsSubject.value;
|
|
1355
|
+
// ✅ لا تفتح الكل عند مسح البحث
|
|
1356
|
+
this.setExpandedRecursive(items, false);
|
|
1357
|
+
this._menuItemsSubject.next([...items]);
|
|
1254
1358
|
}
|
|
1255
1359
|
getSecondToLastLevel(items) {
|
|
1256
1360
|
const result = [];
|
|
1257
1361
|
const traverse = (nodes) => {
|
|
1258
1362
|
for (const node of nodes) {
|
|
1259
1363
|
if (node.items && node.items.length > 0) {
|
|
1260
|
-
// Check if any child has its own children
|
|
1261
1364
|
const hasGrandChildren = node.items.some(c => c.items && c.items.length > 0);
|
|
1262
1365
|
if (!hasGrandChildren) {
|
|
1263
|
-
// Node is right before the last level
|
|
1264
1366
|
result.push(node);
|
|
1265
1367
|
}
|
|
1266
1368
|
else {
|
|
@@ -1273,23 +1375,11 @@ class RoutesComponent {
|
|
|
1273
1375
|
return result;
|
|
1274
1376
|
}
|
|
1275
1377
|
onParentClick(item) {
|
|
1276
|
-
// toggle expand
|
|
1277
1378
|
item.expanded = !item.expanded;
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
// const pathSegments = item.routerLink
|
|
1283
|
-
// ? (Array.isArray(item.routerLink) ? item.routerLink : item.routerLink.split('/').filter(Boolean))
|
|
1284
|
-
// : [];
|
|
1285
|
-
// this.router.navigate(pathSegments);
|
|
1286
|
-
// } else if (item.routerLink) {
|
|
1287
|
-
// const pathSegments = Array.isArray(item.routerLink) ? item.routerLink : item.routerLink.split('/').filter(Boolean);
|
|
1288
|
-
// this.router.navigate(pathSegments);
|
|
1289
|
-
// }
|
|
1290
|
-
// this.subSidebarVisible = true;
|
|
1291
|
-
}
|
|
1292
|
-
onResize() { this.checkViewport(); }
|
|
1379
|
+
}
|
|
1380
|
+
onResize() {
|
|
1381
|
+
this.checkViewport();
|
|
1382
|
+
}
|
|
1293
1383
|
checkViewport() {
|
|
1294
1384
|
this.isMobile = window.innerWidth < 1024;
|
|
1295
1385
|
if (this.isMobile) {
|
|
@@ -1298,6 +1388,7 @@ class RoutesComponent {
|
|
|
1298
1388
|
}
|
|
1299
1389
|
else {
|
|
1300
1390
|
this.sidebarVisible = true;
|
|
1391
|
+
// ✅ خلي الشجرة ظاهرة في الديسكتوب
|
|
1301
1392
|
this.subSidebarVisible = true;
|
|
1302
1393
|
}
|
|
1303
1394
|
}
|
|
@@ -1321,7 +1412,7 @@ class RoutesComponent {
|
|
|
1321
1412
|
if (item.items && item.items.length > 0) {
|
|
1322
1413
|
const found = this.expandPath(item.items, target);
|
|
1323
1414
|
if (found) {
|
|
1324
|
-
item.expanded = true;
|
|
1415
|
+
item.expanded = true;
|
|
1325
1416
|
return true;
|
|
1326
1417
|
}
|
|
1327
1418
|
}
|
|
@@ -1365,14 +1456,7 @@ class RoutesComponent {
|
|
|
1365
1456
|
closeMenu() {
|
|
1366
1457
|
this.subSidebarVisible = false;
|
|
1367
1458
|
this.sidebarVisible = false;
|
|
1368
|
-
|
|
1369
|
-
// items.forEach(item => item.expanded = false);
|
|
1370
|
-
// });
|
|
1371
|
-
}
|
|
1372
|
-
// @HostListener('document:keydown.escape')
|
|
1373
|
-
// onEsc() {
|
|
1374
|
-
// this.closeMenu();
|
|
1375
|
-
// }
|
|
1459
|
+
}
|
|
1376
1460
|
onNavigate() {
|
|
1377
1461
|
if (this.isMobile) {
|
|
1378
1462
|
this.closeMenu();
|
|
@@ -1387,9 +1471,8 @@ class RoutesComponent {
|
|
|
1387
1471
|
const item = {
|
|
1388
1472
|
label: route.name,
|
|
1389
1473
|
icon: route.iconClass,
|
|
1390
|
-
// routerLink: route.path ? [route.path] : undefined,
|
|
1391
1474
|
title: route.name,
|
|
1392
|
-
expanded: false
|
|
1475
|
+
expanded: false // ✅ بدل false، افتح كل عنصر افتراضياً
|
|
1393
1476
|
};
|
|
1394
1477
|
if (route.isExternal) {
|
|
1395
1478
|
item.url = route.path;
|
|
@@ -1403,25 +1486,9 @@ class RoutesComponent {
|
|
|
1403
1486
|
if (this.routesService.hasChildren(route.name)) {
|
|
1404
1487
|
item.items = this.buildItems(route.children ?? []);
|
|
1405
1488
|
}
|
|
1406
|
-
else {
|
|
1407
|
-
// TODO: check if grant permission
|
|
1408
|
-
// if(){
|
|
1409
|
-
// item['actionButtons']= [
|
|
1410
|
-
// {
|
|
1411
|
-
// icon: 'pi pi-plus',
|
|
1412
|
-
// tooltip: 'ADD',
|
|
1413
|
-
// click: (item:any, event:any) => {
|
|
1414
|
-
// this.router.navigate([route.path,'add']);
|
|
1415
|
-
// },
|
|
1416
|
-
// visible: (item:any) => true
|
|
1417
|
-
// }
|
|
1418
|
-
// ];
|
|
1419
|
-
// }
|
|
1420
|
-
}
|
|
1421
1489
|
return item;
|
|
1422
1490
|
}
|
|
1423
1491
|
hasPermission(policy) {
|
|
1424
|
-
// implement using permission service
|
|
1425
1492
|
return true;
|
|
1426
1493
|
}
|
|
1427
1494
|
getLinkProps(item) {
|
|
@@ -1433,12 +1500,28 @@ class RoutesComponent {
|
|
|
1433
1500
|
addRoute: item.addRoute ?? ''
|
|
1434
1501
|
};
|
|
1435
1502
|
}
|
|
1503
|
+
showTreeSearch = false;
|
|
1504
|
+
toggleTreeSearch() {
|
|
1505
|
+
this.showTreeSearch = !this.showTreeSearch;
|
|
1506
|
+
if (!this.showTreeSearch) {
|
|
1507
|
+
this.clearSearch();
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1436
1510
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: RoutesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1437
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: RoutesComponent, isStandalone: true, selector: "app-routes", host: { listeners: { "window:resize": "onResize()" } }, ngImport: i0, template: "<aside class=\"flex h-screen bg-white dark:bg-gray-900 transition-all duration-300\"\n [ngClass]=\"{ 'w-0 overflow-hidden': !sidebarVisible && isMobile }\">\n\n <!-- \uD83C\uDFA8 \u0627\u0644\u0634\u0631\u064A\u0637 \u0627\u0644\u062C\u0627\u0646\u0628\u064A \u0627\u0644\u0631\u0626\u064A\u0633\u064A -->\n <div\n class=\"flex flex-col justify-between pt-4 pb-2 w-16 border-l shadow-xl\n bg-gradient-to-b from-primary-500 via-primary-600 to-primary-700\n text-white rounded-r-3xl\">\n\n <!-- \uD83D\uDD1D \u0627\u0644\u0623\u0639\u0644\u0649 -->\n <div class=\"flex flex-col items-center gap-4\">\n <img src=\"/assets/logo.png\" alt=\"Logo\"\n class=\"w-9 h-9 mt-1 rounded-lg shadow-sm\"/>\n\n <!-- \u0632\u0631 \u0627\u0644\u0642\u0627\u0626\u0645\u0629 -->\n <!-- [pTooltip]=\"'TOGGLE_MENU' | translate\" -->\n <button (click)=\"toggleAll()\"\n tooltipPosition=\"right\"\n class=\"text-white hover:scale-110 transition-transform duration-200\">\n <i class=\"pi pi-bars text-lg\"></i>\n </button>\n\n <!-- \u0623\u064A\u0642\u0648\u0646\u0627\u062A -->\n @for (item of secondToLastLevel$ | async; track item) {\n <div class=\"relative flex flex-col items-center\">\n <!-- \u0627\u0644\u0623\u064A\u0642\u0648\u0646\u0629 -->\n <div (click)=\"onMainClick(item)\"\n [pTooltip]=\"item.label | translate\"\n tooltipPosition=\"right\"\n class=\"relative flex items-center justify-center w-10 h-10 rounded-xl cursor-pointer\n hover:bg-white/20 transition-all duration-200\"\n [ngClass]=\"{ 'bg-white/30 scale-105 shadow-inner': item.expanded }\">\n <i [class]=\"item.icon + ' text-xl'\"></i>\n </div>\n </div>\n }\n </div>\n\n <!-- \u2699\uFE0F \u0627\u0644\u0623\u0633\u0641\u0644 -->\n <div class=\"flex flex-col items-center pb-3 text-white/80\">\n <i class=\"pi pi-cog text-lg hover:text-white cursor-pointer transition\"></i>\n </div>\n </div>\n\n <!-- \uD83D\uDCCB \u0627\u0644\u0642\u0627\u0626\u0645\u0629 \u0627\u0644\u0641\u0631\u0639\u064A\u0629 -->\n @if (subSidebarVisible) {\n <div\n class=\"w-[290px] max-w-[290px] min-w-[260px] border-l border-gray-200 dark:border-gray-700 glass-bg animate-slideIn\n shadow-2xl rounded-l-3xl p-4 rtl:text-right overflow-y-auto overflow-x-hidden transition-all duration-300\"\n [ngClass]=\"{ 'absolute top-0 right-16 h-full z-40': isMobile }\">\n <!-- \u0632\u0631 \u0631\u062C\u0648\u0639 -->\n <button (click)=\"closeMenu()\"\n class=\"flex items-center gap-2 mb-4 text-gray-500 dark:text-gray-300 hover:text-primary-600 transition\">\n <i class=\"pi\" [ngClass]=\"isMobile ? 'pi-angle-right' : 'pi-angle-right'\"></i>\n <span>{{ 'back' | translate }}</span>\n </button>\n <!-- Recursive rendering -->\n @if (menuItems$ | async; as menuItems) {\n <ng-container *ngTemplateOutlet=\"renderMenu; context:{ $implicit: menuItems, level: 1 }\"></ng-container>\n}\n\n<ng-template #renderMenu let-items let-level=\"level\">\n @for (item of items; track item) {\n\n @if (!item.items?.length) {\n @let link = getLinkProps(item);\n <div class=\"mb-1\">\n @if (link.isExternal) {\n <a [href]=\"link.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n (click)=\"$event.stopPropagation()\"\n class=\"flex items-center gap-2 px-3 py-2 rounded-lg transition-all hover:bg-primary-50 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-200\">\n <i [class]=\"item.icon + ' text-base'\"></i>\n <span class=\"min-w-0 break-words whitespace-normal\">{{ item.label | translate }}</span>\n <i class=\"pi pi-external-link text-[10px] opacity-50\"></i>\n </a>\n } @else {\n <div class=\"flex items-center gap-2\">\n <a [routerLink]=\"link.routerLink\"\n (click)=\"onNavigate()\"\n routerLinkActive=\"active-link\"\n class=\"flex-1 min-w-0 flex items-center gap-2 px-2 py-1 rounded-lg transition-all hover:bg-primary-50 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-200\">\n <i [class]=\"item.icon + ' text-base'\"></i>\n <span class=\"min-w-0 break-words whitespace-normal\">\n {{ item.label | translate }}</span>\n </a>\n\n@if (link.addRoute) {\n <a\n [routerLink]=\"[link.addRoute]\"\n (click)=\"$event.stopPropagation(); onNavigate()\"\n class=\"shrink-0 inline-flex items-center justify-center w-7 h-7 rounded-full text-gray-400 hover:text-primary-500 hover:bg-primary-50 dark:text-gray-500 dark:hover:text-primary-400 dark:hover:bg-primary-900/20 transition-all duration-200\"\n [pTooltip]=\"'ADD' | translate\"\n tooltipPosition=\"top\">\n <i class=\"pi pi-plus text-xs\"></i>\n </a>\n}\n </div>\n }\n</div>\n}\n\n @if (item.items?.length) {\n <div class=\"mb-1\">\n\n <div\n (click)=\"onParentClick(item)\"\n [style.font-size.rem]=\"1.1 - (level * 0.05)\"\n [ngClass]=\"{\n 'font-bold': level === 1,\n 'font-semibold': level === 2,\n 'font-medium': level >= 3,\n 'bg-primary-50 text-primary-700 border-r-4 border-primary-500': item.expanded\n }\"\n class=\"flex justify-between items-center py-2 px-3 rounded-lg cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800 transition text-gray-800 dark:text-gray-200\">\n\n <div class=\"flex items-center gap-2\">\n\n <i [class]=\"item.icon + ' text-base'\"></i>\n\n <span>\n {{ item.label | translate }}\n </span>\n\n </div>\n\n <i\n class=\"pi\"\n [ngClass]=\"item.expanded ? 'pi-chevron-down' : 'pi-chevron-left'\"\n style=\"font-size:0.6rem;\">\n </i>\n\n </div>\n\n @if (item.expanded) {\n <div class=\"mr-4 border-r border-gray-200 dark:border-gray-700 pr-2 mt-1\">\n\n <ng-container\n *ngTemplateOutlet=\"renderMenu; context:{ $implicit: item.items, level: level + 1 }\">\n </ng-container>\n\n </div>\n }\n\n </div>\n }\n\n }\n</ng-template>\n\n </div>\n}\n\n</aside>\n\n<!-- \uD83C\uDF1F \u0627\u0644\u0632\u0631 \u0627\u0644\u0639\u0627\u0626\u0645 \u0627\u0644\u062D\u062F\u064A\u062B -->\n@if (isMobile && !sidebarVisible) {\n <button\n class=\"floating-btn\"\n (click)=\"openMenu()\"\n pTooltip=\"{{ 'MENU.OPEN' | translate }}\"\n tooltipPosition=\"top\">\n <img src=\"/assets/logo.png\" alt=\"App Icon\" />\n </button>\n}\n", styles: ["@charset \"UTF-8\";@keyframes slideIn{0%{transform:translate(60px);opacity:0}to{transform:translate(0);opacity:1}}.animate-slideIn{animation:slideIn .35s cubic-bezier(.25,1,.5,1)}.glass-bg{background:#ffffffbf;backdrop-filter:blur(16px) saturate(180%);-webkit-backdrop-filter:blur(16px) saturate(180%);border:1px solid rgba(255,255,255,.25)}@media(max-width:1024px){aside{position:fixed;top:0;right:0;height:100vh;z-index:50}}.floating-btn{position:fixed;bottom:1.25rem;right:1.25rem;z-index:60;width:60px;height:60px;border-radius:50%;background:linear-gradient(135deg,var(--p-primary-500),var(--p-primary-700));box-shadow:0 4px 18px #00000040;display:flex;align-items:center;justify-content:center;transition:all .3s ease}.floating-btn:hover{transform:scale(1.1) rotate(5deg)}.floating-btn img{width:28px;height:28px;border-radius:10px}.active-link{background-color:var(--p-primary-500)!important;color:#fff!important;font-weight:600;box-shadow:0 4px 6px -1px #0000001a;transform:translate(-3px)}.active-link i{color:#fff!important}.active-item-link{background:linear-gradient(to left,var(--p-primary-50),transparent);color:var(--p-primary-600)!important;position:relative;border-right:3px solid var(--p-primary-500);border-radius:0 12px 12px 0}.active-item-link i{color:var(--p-primary-500);filter:drop-shadow(0 0 5px rgba(var(--p-primary-500-rgb),.4))}.active-item-link span{font-weight:700}.animate-slideIn{animation:slideIn .3s ease-out}@keyframes slideIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.glass-bg::-webkit-scrollbar{width:4px}.glass-bg::-webkit-scrollbar-thumb{background:#0000001a;border-radius:10px}.active-link{background-color:var(--p-primary-50)!important;color:var(--p-primary-700)!important;border-right:4px solid var(--p-primary-500)!important;border-radius:4px 12px 12px 4px!important}.active-link span{font-weight:800!important}.active-link i{color:var(--p-primary-600)!important;transform:scale(1.1)}aside{-webkit-font-smoothing:antialiased;letter-spacing:-.01em}.dark .active-link{background-color:rgba(var(--p-primary-500-rgb),.15)!important;color:var(--p-primary-300)!important}.submenu{animation:menuOpen .25s ease}@keyframes menuOpen{0%{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}}aside{box-shadow:0 10px 40px #00000026}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2$2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i2$2.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i3$2.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "ngmodule", type: StyleClassModule }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
1511
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: RoutesComponent, isStandalone: true, selector: "app-routes", host: { listeners: { "window:resize": "onResize()" } }, ngImport: i0, template: "<aside class=\"flex h-screen bg-white dark:bg-gray-900 transition-all duration-300\"\r\n [ngClass]=\"{ 'w-0 overflow-hidden': !sidebarVisible && isMobile }\">\r\n\r\n <!-- \uD83C\uDFA8 \u0627\u0644\u0634\u0631\u064A\u0637 \u0627\u0644\u062C\u0627\u0646\u0628\u064A \u0627\u0644\u0631\u0626\u064A\u0633\u064A -->\r\n <div\r\n class=\"flex flex-col justify-between pt-4 pb-2 w-16 border-l shadow-xl\r\n bg-gradient-to-b from-primary-500 via-primary-600 to-primary-700\r\n text-white rounded-r-3xl\">\r\n\r\n <!-- \uD83D\uDD1D \u0627\u0644\u0623\u0639\u0644\u0649 -->\r\n <div class=\"flex flex-col items-center gap-4\">\r\n <img src=\"/assets/logo.png\" alt=\"Logo\"\r\n class=\"w-9 h-9 mt-1 rounded-lg shadow-sm\"/>\r\n\r\n <!-- \u0632\u0631 \u0627\u0644\u0642\u0627\u0626\u0645\u0629 -->\r\n <!-- [pTooltip]=\"'TOGGLE_MENU' | translate\" -->\r\n <button (click)=\"toggleAll()\"\r\n tooltipPosition=\"right\"\r\n class=\"text-white hover:scale-110 transition-transform duration-200\">\r\n <i class=\"pi pi-bars text-lg\"></i>\r\n </button>\r\n\r\n <!-- \u0623\u064A\u0642\u0648\u0646\u0627\u062A -->\r\n @for (item of secondToLastLevel$ | async; track item) {\r\n <div class=\"relative flex flex-col items-center\">\r\n <!-- \u0627\u0644\u0623\u064A\u0642\u0648\u0646\u0629 -->\r\n <div (click)=\"onMainClick(item)\"\r\n [pTooltip]=\"item.label | translate\"\r\n tooltipPosition=\"right\"\r\n class=\"relative flex items-center justify-center w-10 h-10 rounded-xl cursor-pointer\r\n hover:bg-white/20 transition-all duration-200\"\r\n [ngClass]=\"{ 'bg-white/30 scale-105 shadow-inner': item.expanded }\">\r\n <i [class]=\"item.icon + ' text-xl'\"></i>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- \u2699\uFE0F \u0627\u0644\u0623\u0633\u0641\u0644 -->\r\n <div class=\"flex flex-col items-center pb-3 text-white/80\">\r\n <i class=\"pi pi-cog text-lg hover:text-white cursor-pointer transition\"></i>\r\n </div>\r\n </div>\r\n\r\n <!-- \uD83D\uDCCB \u0627\u0644\u0642\u0627\u0626\u0645\u0629 \u0627\u0644\u0641\u0631\u0639\u064A\u0629 -->\r\n @if (subSidebarVisible) {\r\n <div\r\n class=\"w-[290px] max-w-[290px] min-w-[260px] border-l border-gray-200 dark:border-gray-700 glass-bg animate-slideIn\r\n shadow-2xl rounded-l-3xl p-4 rtl:text-right overflow-y-auto overflow-x-hidden transition-all duration-300\"\r\n [ngClass]=\"{ 'absolute top-0 right-16 h-full z-40': isMobile }\">\r\n <!-- \u0632\u0631 \u0631\u062C\u0648\u0639 -->\r\n <!-- \uD83D\uDD1D \u0631\u0623\u0633 \u0627\u0644\u0634\u062C\u0631\u0629 -->\r\n<!-- \uD83D\uDD1D \u0631\u0623\u0633 \u0627\u0644\u0634\u062C\u0631\u0629 -->\r\n<div class=\"tree-header mb-1\">\r\n\r\n <button\r\n type=\"button\"\r\n (click)=\"closeMenu()\"\r\n class=\"tree-back-btn\">\r\n <i class=\"pi pi-angle-right\"></i>\r\n <span>{{ 'back' | translate }}</span>\r\n </button>\r\n\r\n <div class=\"tree-header-actions\">\r\n\r\n <button\r\n type=\"button\"\r\n class=\"tree-mini-btn\"\r\n (click)=\"expandAll()\"\r\n pTooltip=\"\u0641\u062A\u062D \u0627\u0644\u0634\u062C\u0631\u0629 \u0643\u0627\u0645\u0644\u0629\"\r\n tooltipPosition=\"top\">\r\n <i class=\"pi pi-plus\"></i>\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"tree-mini-btn\"\r\n (click)=\"collapseAll()\"\r\n pTooltip=\"\u0625\u063A\u0644\u0627\u0642 \u0627\u0644\u0634\u062C\u0631\u0629 \u0643\u0627\u0645\u0644\u0629\"\r\n tooltipPosition=\"top\">\r\n <i class=\"pi pi-minus\"></i>\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"tree-search-toggle\"\r\n [ngClass]=\"{ 'active': showTreeSearch }\"\r\n (click)=\"toggleTreeSearch()\"\r\n pTooltip=\"\u0628\u062D\u062B \u062F\u0627\u062E\u0644 \u0627\u0644\u0634\u0627\u0634\u0627\u062A\"\r\n tooltipPosition=\"top\">\r\n <i class=\"pi pi-search\"></i>\r\n </button>\r\n\r\n </div>\r\n\r\n</div>\r\n\r\n@if (showTreeSearch) {\r\n <div class=\"tree-search-panel mb-4 animate-slideIn\">\r\n <div class=\"tree-search\">\r\n <i class=\"pi pi-search\"></i>\r\n\r\n <input\r\n type=\"text\"\r\n [(ngModel)]=\"searchText\"\r\n (input)=\"onSearchChange()\"\r\n placeholder=\"\u0628\u062D\u062B \u062F\u0627\u062E\u0644 \u0627\u0644\u0634\u0627\u0634\u0627\u062A...\"\r\n class=\"tree-search-input\" />\r\n\r\n @if (searchText) {\r\n <button\r\n type=\"button\"\r\n class=\"tree-search-clear\"\r\n (click)=\"clearSearch()\">\r\n <i class=\"pi pi-times\"></i>\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n}\r\n\r\n\r\n <!-- Recursive rendering -->\r\n @if (menuItems$ | async; as menuItems) {\r\n <ng-container *ngTemplateOutlet=\"renderMenu; context:{ $implicit: menuItems, level: 1 }\"></ng-container>\r\n}\r\n\r\n<ng-template #renderMenu let-items let-level=\"level\">\r\n @for (item of items; track item) {\r\n\r\n @if (!item.items?.length) {\r\n @let link = getLinkProps(item);\r\n <div class=\"mb-1\">\r\n @if (link.isExternal) {\r\n <a [href]=\"link.href\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n (click)=\"$event.stopPropagation()\"\r\n class=\"flex items-center gap-2 px-3 py-2 rounded-lg transition-all hover:bg-primary-50 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-200\">\r\n <i [class]=\"item.icon + ' text-base'\"></i>\r\n <span class=\"min-w-0 break-words whitespace-normal\">{{ item.label | translate }}</span>\r\n <i class=\"pi pi-external-link text-[10px] opacity-50\"></i>\r\n </a>\r\n } @else {\r\n <div class=\"flex items-center gap-2\">\r\n <a [routerLink]=\"link.routerLink\"\r\n (click)=\"onNavigate()\"\r\n routerLinkActive=\"active-link\"\r\n [ngClass]=\"{ 'search-match': isSearchMatch(item) }\"\r\n class=\"flex-1 min-w-0 flex items-center gap-2 px-2 py-1 rounded-lg transition-all hover:bg-primary-50 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-200\">\r\n <i [class]=\"item.icon + ' text-base'\"></i>\r\n <span class=\"min-w-0 break-words whitespace-normal\">\r\n {{ item.label | translate }}</span>\r\n </a>\r\n\r\n@if (link.addRoute) {\r\n <a\r\n [routerLink]=\"[link.addRoute]\"\r\n (click)=\"$event.stopPropagation(); onNavigate()\"\r\n class=\"shrink-0 inline-flex items-center justify-center w-7 h-7 rounded-full text-gray-400 hover:text-primary-500 hover:bg-primary-50 dark:text-gray-500 dark:hover:text-primary-400 dark:hover:bg-primary-900/20 transition-all duration-200\"\r\n [pTooltip]=\"'ADD' | translate\"\r\n tooltipPosition=\"top\">\r\n <i class=\"pi pi-plus text-xs\"></i>\r\n </a>\r\n}\r\n </div>\r\n }\r\n</div>\r\n}\r\n\r\n @if (item.items?.length) {\r\n <div class=\"mb-1\">\r\n\r\n <div\r\n (click)=\"onParentClick(item)\"\r\n [style.font-size.rem]=\"1.1 - (level * 0.05)\"\r\n[ngClass]=\"{\r\n 'font-bold': level === 1,\r\n 'font-semibold': level === 2,\r\n 'font-medium': level >= 3,\r\n 'bg-primary-50 text-primary-700 border-r-4 border-primary-500': item.expanded,\r\n 'search-match': isSearchMatch(item)\r\n}\"\r\n class=\"flex justify-between items-center py-2 px-3 rounded-lg cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800 transition text-gray-800 dark:text-gray-200\">\r\n\r\n <div class=\"flex items-center gap-2\">\r\n\r\n <i [class]=\"item.icon + ' text-base'\"></i>\r\n\r\n <span>\r\n {{ item.label | translate }}\r\n </span>\r\n\r\n </div>\r\n\r\n <i\r\n class=\"pi\"\r\n [ngClass]=\"item.expanded ? 'pi-chevron-down' : 'pi-chevron-left'\"\r\n style=\"font-size:0.6rem;\">\r\n </i>\r\n\r\n </div>\r\n\r\n @if (item.expanded) {\r\n <div class=\"mr-4 border-r border-gray-200 dark:border-gray-700 pr-2 mt-1\">\r\n\r\n <ng-container\r\n *ngTemplateOutlet=\"renderMenu; context:{ $implicit: item.items, level: level + 1 }\">\r\n </ng-container>\r\n\r\n </div>\r\n }\r\n\r\n </div>\r\n }\r\n\r\n }\r\n</ng-template>\r\n\r\n </div>\r\n}\r\n\r\n</aside>\r\n\r\n<!-- \uD83C\uDF1F \u0627\u0644\u0632\u0631 \u0627\u0644\u0639\u0627\u0626\u0645 \u0627\u0644\u062D\u062F\u064A\u062B -->\r\n@if (isMobile && !sidebarVisible) {\r\n <button\r\n class=\"floating-btn\"\r\n (click)=\"openMenu()\"\r\n pTooltip=\"{{ 'MENU.OPEN' | translate }}\"\r\n tooltipPosition=\"top\">\r\n <img src=\"/assets/logo.png\" alt=\"App Icon\" />\r\n </button>\r\n}\r\n", styles: ["@charset \"UTF-8\";@keyframes slideIn{0%{transform:translate(60px);opacity:0}to{transform:translate(0);opacity:1}}.animate-slideIn{animation:slideIn .35s cubic-bezier(.25,1,.5,1)}.glass-bg{background:#ffffffbf;backdrop-filter:blur(16px) saturate(180%);-webkit-backdrop-filter:blur(16px) saturate(180%);border:1px solid rgba(255,255,255,.25)}@media(max-width:1024px){aside{position:fixed;top:0;right:0;height:100vh;z-index:50}}.floating-btn{position:fixed;bottom:1.25rem;right:1.25rem;z-index:60;width:60px;height:60px;border-radius:50%;background:linear-gradient(135deg,var(--p-primary-500),var(--p-primary-700));box-shadow:0 4px 18px #00000040;display:flex;align-items:center;justify-content:center;transition:all .3s ease}.floating-btn:hover{transform:scale(1.1) rotate(5deg)}.floating-btn img{width:28px;height:28px;border-radius:10px}.active-link{background-color:var(--p-primary-500)!important;color:#fff!important;font-weight:600;box-shadow:0 4px 6px -1px #0000001a;transform:translate(-3px)}.active-link i{color:#fff!important}.active-item-link{background:linear-gradient(to left,var(--p-primary-50),transparent);color:var(--p-primary-600)!important;position:relative;border-right:3px solid var(--p-primary-500);border-radius:0 12px 12px 0}.active-item-link i{color:var(--p-primary-500);filter:drop-shadow(0 0 5px rgba(var(--p-primary-500-rgb),.4))}.active-item-link span{font-weight:700}.animate-slideIn{animation:slideIn .3s ease-out}@keyframes slideIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.glass-bg::-webkit-scrollbar{width:4px}.glass-bg::-webkit-scrollbar-thumb{background:#0000001a;border-radius:10px}.active-link{background-color:var(--p-primary-50)!important;color:var(--p-primary-700)!important;border-right:4px solid var(--p-primary-500)!important;border-radius:4px 12px 12px 4px!important}.active-link span{font-weight:800!important}.active-link i{color:var(--p-primary-600)!important;transform:scale(1.1)}aside{-webkit-font-smoothing:antialiased;letter-spacing:-.01em}.dark .active-link{background-color:rgba(var(--p-primary-500-rgb),.15)!important;color:var(--p-primary-300)!important}.submenu{animation:menuOpen .25s ease}@keyframes menuOpen{0%{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}}aside{box-shadow:0 10px 40px #00000026}.tree-back-btn{height:2.25rem;padding:0 .35rem 0 .75rem;display:inline-flex;align-items:center;gap:.35rem;color:#64748b;font-weight:700;border-radius:999px;transition:all .2s ease}.tree-header{display:flex;align-items:center;justify-content:space-between;gap:.75rem}.tree-back-btn{height:2.35rem;padding:0 .45rem 0 .85rem;display:inline-flex;align-items:center;gap:.4rem;color:#64748b;font-size:.86rem;font-weight:700;border-radius:999px;transition:all .22s ease}.tree-back-btn:hover{color:var(--p-primary-600);background:var(--p-primary-50)}.tree-back-btn i{font-size:.85rem}.tree-header-actions{display:inline-flex;align-items:center;gap:.3rem}.tree-mini-btn,.tree-search-toggle{width:2rem;height:2rem;border-radius:.8rem;display:inline-flex;align-items:center;justify-content:center;color:#64748b;background:#f8fafcd9;border:1px solid rgba(148,163,184,.24);transition:all .2s ease}.tree-mini-btn i,.tree-search-toggle i{font-size:.72rem}.tree-mini-btn:hover,.tree-search-toggle:hover{color:var(--p-primary-600);background:var(--p-primary-50);border-color:rgba(var(--p-primary-500-rgb),.25);transform:translateY(-1px)}.tree-search-toggle{color:var(--p-primary-600);background:rgba(var(--p-primary-500-rgb),.08);border-color:rgba(var(--p-primary-500-rgb),.18)}.tree-search-toggle.active{color:#fff;background:linear-gradient(135deg,var(--p-primary-500),var(--p-primary-600));border-color:transparent;box-shadow:0 8px 18px rgba(var(--p-primary-500-rgb),.22)}.tree-search-panel{padding:.65rem;border-radius:1.15rem;background:#ffffff94;border:1px solid rgba(255,255,255,.45);box-shadow:0 10px 30px #0f172a14;backdrop-filter:blur(14px) saturate(160%);-webkit-backdrop-filter:blur(14px) saturate(160%)}.tree-search{position:relative;display:flex;align-items:center}.tree-search i.pi-search{position:absolute;right:.85rem;color:var(--p-primary-500);font-size:.85rem;z-index:1}.tree-search-input{width:100%;height:2.45rem;padding:0 2.35rem 0 2.2rem;border-radius:999px;border:1px solid rgba(148,163,184,.35);background:#ffffffd1;color:#334155;font-size:.86rem;outline:none;transition:all .25s ease}.tree-search-input:focus{border-color:var(--p-primary-400);box-shadow:0 0 0 4px rgba(var(--p-primary-500-rgb),.12);background:#fff}.tree-search-clear{position:absolute;left:.55rem;width:1.75rem;height:1.75rem;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;color:#64748b;background:#f1f5f9e6;transition:all .2s ease}.tree-search-clear:hover{color:var(--p-primary-600);background:var(--p-primary-50);transform:scale(1.05)}.tree-search-icon{position:absolute;right:.85rem;color:#94a3b8;font-size:.85rem;pointer-events:none}.tree-search-input{width:100%;height:2.45rem;padding:0 2.35rem 0 2.2rem;border-radius:.95rem;border:1px solid rgba(148,163,184,.28);background:#f8fafcd1;color:#334155;font-size:.86rem;outline:none;transition:all .22s ease}.tree-search-input:focus{border-color:rgba(var(--p-primary-500-rgb),.45);background:#fff;box-shadow:0 0 0 3px rgba(var(--p-primary-500-rgb),.1)}.tree-search-input::placeholder{color:#94a3b8}.tree-search-clear{position:absolute;left:.55rem;width:1.65rem;height:1.65rem;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;color:#94a3b8;background:transparent;transition:all .2s ease}.tree-search-clear:hover{color:var(--p-primary-600);background:var(--p-primary-50)}.tree-search-clear i{font-size:.7rem}.dark .tree-back-btn{color:#cbd5e1}.dark .tree-back-btn:hover{color:var(--p-primary-300);background:rgba(var(--p-primary-500-rgb),.12)}.dark .tree-header-actions{background:#1f2937b8;border-color:#94a3b824}.dark .tree-icon-btn{color:#cbd5e1}.dark .tree-icon-btn:hover{color:#fff;background:var(--p-primary-600)}.dark .tree-search-icon{color:#64748b}.dark .tree-search-input{background:#1f2937bd;border-color:#94a3b829;color:#e5e7eb}.dark .tree-search-input:focus{background:#111827eb;border-color:rgba(var(--p-primary-500-rgb),.48)}.dark .tree-search-input::placeholder{color:#64748b}.dark .tree-search-clear{color:#94a3b8}.dark .tree-search-clear:hover{color:var(--p-primary-300);background:rgba(var(--p-primary-500-rgb),.12)}.search-match{background:linear-gradient(to left,rgba(var(--p-primary-500-rgb),.16),transparent)!important;color:var(--p-primary-700)!important;border-right:3px solid var(--p-primary-500)!important;box-shadow:inset 0 0 0 1px rgba(var(--p-primary-500-rgb),.08)}.search-match span{font-weight:800!important}.search-match i{color:var(--p-primary-600)!important}.dark .tree-toolbar{background:#111827b8;border-color:#ffffff14}.dark .tree-search-input{background:#1f2937cc;border-color:#94a3b82e;color:#e5e7eb}.dark .tree-search-input:focus{background:#111827f2}.dark .tree-search-clear{background:#374151e6;color:#cbd5e1}.dark .tree-action-btn{background:rgba(var(--p-primary-500-rgb),.12);color:var(--p-primary-300);border-color:rgba(var(--p-primary-500-rgb),.22)}.dark .tree-action-btn:hover{background:var(--p-primary-600);color:#fff}.dark .search-match{background:rgba(var(--p-primary-500-rgb),.18)!important;color:var(--p-primary-300)!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i2$1.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: // ✅ أضف هذا
|
|
1512
|
+
TooltipModule }, { kind: "directive", type: i4$1.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "ngmodule", type: StyleClassModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
1438
1513
|
}
|
|
1439
1514
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: RoutesComponent, decorators: [{
|
|
1440
1515
|
type: Component,
|
|
1441
|
-
args: [{ selector: 'app-routes', standalone: true, imports: [
|
|
1516
|
+
args: [{ selector: 'app-routes', standalone: true, imports: [
|
|
1517
|
+
CommonModule,
|
|
1518
|
+
RouterModule,
|
|
1519
|
+
FormsModule, // ✅ أضف هذا
|
|
1520
|
+
TooltipModule,
|
|
1521
|
+
TranslatePipe,
|
|
1522
|
+
StyleClassModule,
|
|
1523
|
+
ButtonModule
|
|
1524
|
+
], template: "<aside class=\"flex h-screen bg-white dark:bg-gray-900 transition-all duration-300\"\r\n [ngClass]=\"{ 'w-0 overflow-hidden': !sidebarVisible && isMobile }\">\r\n\r\n <!-- \uD83C\uDFA8 \u0627\u0644\u0634\u0631\u064A\u0637 \u0627\u0644\u062C\u0627\u0646\u0628\u064A \u0627\u0644\u0631\u0626\u064A\u0633\u064A -->\r\n <div\r\n class=\"flex flex-col justify-between pt-4 pb-2 w-16 border-l shadow-xl\r\n bg-gradient-to-b from-primary-500 via-primary-600 to-primary-700\r\n text-white rounded-r-3xl\">\r\n\r\n <!-- \uD83D\uDD1D \u0627\u0644\u0623\u0639\u0644\u0649 -->\r\n <div class=\"flex flex-col items-center gap-4\">\r\n <img src=\"/assets/logo.png\" alt=\"Logo\"\r\n class=\"w-9 h-9 mt-1 rounded-lg shadow-sm\"/>\r\n\r\n <!-- \u0632\u0631 \u0627\u0644\u0642\u0627\u0626\u0645\u0629 -->\r\n <!-- [pTooltip]=\"'TOGGLE_MENU' | translate\" -->\r\n <button (click)=\"toggleAll()\"\r\n tooltipPosition=\"right\"\r\n class=\"text-white hover:scale-110 transition-transform duration-200\">\r\n <i class=\"pi pi-bars text-lg\"></i>\r\n </button>\r\n\r\n <!-- \u0623\u064A\u0642\u0648\u0646\u0627\u062A -->\r\n @for (item of secondToLastLevel$ | async; track item) {\r\n <div class=\"relative flex flex-col items-center\">\r\n <!-- \u0627\u0644\u0623\u064A\u0642\u0648\u0646\u0629 -->\r\n <div (click)=\"onMainClick(item)\"\r\n [pTooltip]=\"item.label | translate\"\r\n tooltipPosition=\"right\"\r\n class=\"relative flex items-center justify-center w-10 h-10 rounded-xl cursor-pointer\r\n hover:bg-white/20 transition-all duration-200\"\r\n [ngClass]=\"{ 'bg-white/30 scale-105 shadow-inner': item.expanded }\">\r\n <i [class]=\"item.icon + ' text-xl'\"></i>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- \u2699\uFE0F \u0627\u0644\u0623\u0633\u0641\u0644 -->\r\n <div class=\"flex flex-col items-center pb-3 text-white/80\">\r\n <i class=\"pi pi-cog text-lg hover:text-white cursor-pointer transition\"></i>\r\n </div>\r\n </div>\r\n\r\n <!-- \uD83D\uDCCB \u0627\u0644\u0642\u0627\u0626\u0645\u0629 \u0627\u0644\u0641\u0631\u0639\u064A\u0629 -->\r\n @if (subSidebarVisible) {\r\n <div\r\n class=\"w-[290px] max-w-[290px] min-w-[260px] border-l border-gray-200 dark:border-gray-700 glass-bg animate-slideIn\r\n shadow-2xl rounded-l-3xl p-4 rtl:text-right overflow-y-auto overflow-x-hidden transition-all duration-300\"\r\n [ngClass]=\"{ 'absolute top-0 right-16 h-full z-40': isMobile }\">\r\n <!-- \u0632\u0631 \u0631\u062C\u0648\u0639 -->\r\n <!-- \uD83D\uDD1D \u0631\u0623\u0633 \u0627\u0644\u0634\u062C\u0631\u0629 -->\r\n<!-- \uD83D\uDD1D \u0631\u0623\u0633 \u0627\u0644\u0634\u062C\u0631\u0629 -->\r\n<div class=\"tree-header mb-1\">\r\n\r\n <button\r\n type=\"button\"\r\n (click)=\"closeMenu()\"\r\n class=\"tree-back-btn\">\r\n <i class=\"pi pi-angle-right\"></i>\r\n <span>{{ 'back' | translate }}</span>\r\n </button>\r\n\r\n <div class=\"tree-header-actions\">\r\n\r\n <button\r\n type=\"button\"\r\n class=\"tree-mini-btn\"\r\n (click)=\"expandAll()\"\r\n pTooltip=\"\u0641\u062A\u062D \u0627\u0644\u0634\u062C\u0631\u0629 \u0643\u0627\u0645\u0644\u0629\"\r\n tooltipPosition=\"top\">\r\n <i class=\"pi pi-plus\"></i>\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"tree-mini-btn\"\r\n (click)=\"collapseAll()\"\r\n pTooltip=\"\u0625\u063A\u0644\u0627\u0642 \u0627\u0644\u0634\u062C\u0631\u0629 \u0643\u0627\u0645\u0644\u0629\"\r\n tooltipPosition=\"top\">\r\n <i class=\"pi pi-minus\"></i>\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"tree-search-toggle\"\r\n [ngClass]=\"{ 'active': showTreeSearch }\"\r\n (click)=\"toggleTreeSearch()\"\r\n pTooltip=\"\u0628\u062D\u062B \u062F\u0627\u062E\u0644 \u0627\u0644\u0634\u0627\u0634\u0627\u062A\"\r\n tooltipPosition=\"top\">\r\n <i class=\"pi pi-search\"></i>\r\n </button>\r\n\r\n </div>\r\n\r\n</div>\r\n\r\n@if (showTreeSearch) {\r\n <div class=\"tree-search-panel mb-4 animate-slideIn\">\r\n <div class=\"tree-search\">\r\n <i class=\"pi pi-search\"></i>\r\n\r\n <input\r\n type=\"text\"\r\n [(ngModel)]=\"searchText\"\r\n (input)=\"onSearchChange()\"\r\n placeholder=\"\u0628\u062D\u062B \u062F\u0627\u062E\u0644 \u0627\u0644\u0634\u0627\u0634\u0627\u062A...\"\r\n class=\"tree-search-input\" />\r\n\r\n @if (searchText) {\r\n <button\r\n type=\"button\"\r\n class=\"tree-search-clear\"\r\n (click)=\"clearSearch()\">\r\n <i class=\"pi pi-times\"></i>\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n}\r\n\r\n\r\n <!-- Recursive rendering -->\r\n @if (menuItems$ | async; as menuItems) {\r\n <ng-container *ngTemplateOutlet=\"renderMenu; context:{ $implicit: menuItems, level: 1 }\"></ng-container>\r\n}\r\n\r\n<ng-template #renderMenu let-items let-level=\"level\">\r\n @for (item of items; track item) {\r\n\r\n @if (!item.items?.length) {\r\n @let link = getLinkProps(item);\r\n <div class=\"mb-1\">\r\n @if (link.isExternal) {\r\n <a [href]=\"link.href\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n (click)=\"$event.stopPropagation()\"\r\n class=\"flex items-center gap-2 px-3 py-2 rounded-lg transition-all hover:bg-primary-50 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-200\">\r\n <i [class]=\"item.icon + ' text-base'\"></i>\r\n <span class=\"min-w-0 break-words whitespace-normal\">{{ item.label | translate }}</span>\r\n <i class=\"pi pi-external-link text-[10px] opacity-50\"></i>\r\n </a>\r\n } @else {\r\n <div class=\"flex items-center gap-2\">\r\n <a [routerLink]=\"link.routerLink\"\r\n (click)=\"onNavigate()\"\r\n routerLinkActive=\"active-link\"\r\n [ngClass]=\"{ 'search-match': isSearchMatch(item) }\"\r\n class=\"flex-1 min-w-0 flex items-center gap-2 px-2 py-1 rounded-lg transition-all hover:bg-primary-50 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-200\">\r\n <i [class]=\"item.icon + ' text-base'\"></i>\r\n <span class=\"min-w-0 break-words whitespace-normal\">\r\n {{ item.label | translate }}</span>\r\n </a>\r\n\r\n@if (link.addRoute) {\r\n <a\r\n [routerLink]=\"[link.addRoute]\"\r\n (click)=\"$event.stopPropagation(); onNavigate()\"\r\n class=\"shrink-0 inline-flex items-center justify-center w-7 h-7 rounded-full text-gray-400 hover:text-primary-500 hover:bg-primary-50 dark:text-gray-500 dark:hover:text-primary-400 dark:hover:bg-primary-900/20 transition-all duration-200\"\r\n [pTooltip]=\"'ADD' | translate\"\r\n tooltipPosition=\"top\">\r\n <i class=\"pi pi-plus text-xs\"></i>\r\n </a>\r\n}\r\n </div>\r\n }\r\n</div>\r\n}\r\n\r\n @if (item.items?.length) {\r\n <div class=\"mb-1\">\r\n\r\n <div\r\n (click)=\"onParentClick(item)\"\r\n [style.font-size.rem]=\"1.1 - (level * 0.05)\"\r\n[ngClass]=\"{\r\n 'font-bold': level === 1,\r\n 'font-semibold': level === 2,\r\n 'font-medium': level >= 3,\r\n 'bg-primary-50 text-primary-700 border-r-4 border-primary-500': item.expanded,\r\n 'search-match': isSearchMatch(item)\r\n}\"\r\n class=\"flex justify-between items-center py-2 px-3 rounded-lg cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800 transition text-gray-800 dark:text-gray-200\">\r\n\r\n <div class=\"flex items-center gap-2\">\r\n\r\n <i [class]=\"item.icon + ' text-base'\"></i>\r\n\r\n <span>\r\n {{ item.label | translate }}\r\n </span>\r\n\r\n </div>\r\n\r\n <i\r\n class=\"pi\"\r\n [ngClass]=\"item.expanded ? 'pi-chevron-down' : 'pi-chevron-left'\"\r\n style=\"font-size:0.6rem;\">\r\n </i>\r\n\r\n </div>\r\n\r\n @if (item.expanded) {\r\n <div class=\"mr-4 border-r border-gray-200 dark:border-gray-700 pr-2 mt-1\">\r\n\r\n <ng-container\r\n *ngTemplateOutlet=\"renderMenu; context:{ $implicit: item.items, level: level + 1 }\">\r\n </ng-container>\r\n\r\n </div>\r\n }\r\n\r\n </div>\r\n }\r\n\r\n }\r\n</ng-template>\r\n\r\n </div>\r\n}\r\n\r\n</aside>\r\n\r\n<!-- \uD83C\uDF1F \u0627\u0644\u0632\u0631 \u0627\u0644\u0639\u0627\u0626\u0645 \u0627\u0644\u062D\u062F\u064A\u062B -->\r\n@if (isMobile && !sidebarVisible) {\r\n <button\r\n class=\"floating-btn\"\r\n (click)=\"openMenu()\"\r\n pTooltip=\"{{ 'MENU.OPEN' | translate }}\"\r\n tooltipPosition=\"top\">\r\n <img src=\"/assets/logo.png\" alt=\"App Icon\" />\r\n </button>\r\n}\r\n", styles: ["@charset \"UTF-8\";@keyframes slideIn{0%{transform:translate(60px);opacity:0}to{transform:translate(0);opacity:1}}.animate-slideIn{animation:slideIn .35s cubic-bezier(.25,1,.5,1)}.glass-bg{background:#ffffffbf;backdrop-filter:blur(16px) saturate(180%);-webkit-backdrop-filter:blur(16px) saturate(180%);border:1px solid rgba(255,255,255,.25)}@media(max-width:1024px){aside{position:fixed;top:0;right:0;height:100vh;z-index:50}}.floating-btn{position:fixed;bottom:1.25rem;right:1.25rem;z-index:60;width:60px;height:60px;border-radius:50%;background:linear-gradient(135deg,var(--p-primary-500),var(--p-primary-700));box-shadow:0 4px 18px #00000040;display:flex;align-items:center;justify-content:center;transition:all .3s ease}.floating-btn:hover{transform:scale(1.1) rotate(5deg)}.floating-btn img{width:28px;height:28px;border-radius:10px}.active-link{background-color:var(--p-primary-500)!important;color:#fff!important;font-weight:600;box-shadow:0 4px 6px -1px #0000001a;transform:translate(-3px)}.active-link i{color:#fff!important}.active-item-link{background:linear-gradient(to left,var(--p-primary-50),transparent);color:var(--p-primary-600)!important;position:relative;border-right:3px solid var(--p-primary-500);border-radius:0 12px 12px 0}.active-item-link i{color:var(--p-primary-500);filter:drop-shadow(0 0 5px rgba(var(--p-primary-500-rgb),.4))}.active-item-link span{font-weight:700}.animate-slideIn{animation:slideIn .3s ease-out}@keyframes slideIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.glass-bg::-webkit-scrollbar{width:4px}.glass-bg::-webkit-scrollbar-thumb{background:#0000001a;border-radius:10px}.active-link{background-color:var(--p-primary-50)!important;color:var(--p-primary-700)!important;border-right:4px solid var(--p-primary-500)!important;border-radius:4px 12px 12px 4px!important}.active-link span{font-weight:800!important}.active-link i{color:var(--p-primary-600)!important;transform:scale(1.1)}aside{-webkit-font-smoothing:antialiased;letter-spacing:-.01em}.dark .active-link{background-color:rgba(var(--p-primary-500-rgb),.15)!important;color:var(--p-primary-300)!important}.submenu{animation:menuOpen .25s ease}@keyframes menuOpen{0%{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}}aside{box-shadow:0 10px 40px #00000026}.tree-back-btn{height:2.25rem;padding:0 .35rem 0 .75rem;display:inline-flex;align-items:center;gap:.35rem;color:#64748b;font-weight:700;border-radius:999px;transition:all .2s ease}.tree-header{display:flex;align-items:center;justify-content:space-between;gap:.75rem}.tree-back-btn{height:2.35rem;padding:0 .45rem 0 .85rem;display:inline-flex;align-items:center;gap:.4rem;color:#64748b;font-size:.86rem;font-weight:700;border-radius:999px;transition:all .22s ease}.tree-back-btn:hover{color:var(--p-primary-600);background:var(--p-primary-50)}.tree-back-btn i{font-size:.85rem}.tree-header-actions{display:inline-flex;align-items:center;gap:.3rem}.tree-mini-btn,.tree-search-toggle{width:2rem;height:2rem;border-radius:.8rem;display:inline-flex;align-items:center;justify-content:center;color:#64748b;background:#f8fafcd9;border:1px solid rgba(148,163,184,.24);transition:all .2s ease}.tree-mini-btn i,.tree-search-toggle i{font-size:.72rem}.tree-mini-btn:hover,.tree-search-toggle:hover{color:var(--p-primary-600);background:var(--p-primary-50);border-color:rgba(var(--p-primary-500-rgb),.25);transform:translateY(-1px)}.tree-search-toggle{color:var(--p-primary-600);background:rgba(var(--p-primary-500-rgb),.08);border-color:rgba(var(--p-primary-500-rgb),.18)}.tree-search-toggle.active{color:#fff;background:linear-gradient(135deg,var(--p-primary-500),var(--p-primary-600));border-color:transparent;box-shadow:0 8px 18px rgba(var(--p-primary-500-rgb),.22)}.tree-search-panel{padding:.65rem;border-radius:1.15rem;background:#ffffff94;border:1px solid rgba(255,255,255,.45);box-shadow:0 10px 30px #0f172a14;backdrop-filter:blur(14px) saturate(160%);-webkit-backdrop-filter:blur(14px) saturate(160%)}.tree-search{position:relative;display:flex;align-items:center}.tree-search i.pi-search{position:absolute;right:.85rem;color:var(--p-primary-500);font-size:.85rem;z-index:1}.tree-search-input{width:100%;height:2.45rem;padding:0 2.35rem 0 2.2rem;border-radius:999px;border:1px solid rgba(148,163,184,.35);background:#ffffffd1;color:#334155;font-size:.86rem;outline:none;transition:all .25s ease}.tree-search-input:focus{border-color:var(--p-primary-400);box-shadow:0 0 0 4px rgba(var(--p-primary-500-rgb),.12);background:#fff}.tree-search-clear{position:absolute;left:.55rem;width:1.75rem;height:1.75rem;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;color:#64748b;background:#f1f5f9e6;transition:all .2s ease}.tree-search-clear:hover{color:var(--p-primary-600);background:var(--p-primary-50);transform:scale(1.05)}.tree-search-icon{position:absolute;right:.85rem;color:#94a3b8;font-size:.85rem;pointer-events:none}.tree-search-input{width:100%;height:2.45rem;padding:0 2.35rem 0 2.2rem;border-radius:.95rem;border:1px solid rgba(148,163,184,.28);background:#f8fafcd1;color:#334155;font-size:.86rem;outline:none;transition:all .22s ease}.tree-search-input:focus{border-color:rgba(var(--p-primary-500-rgb),.45);background:#fff;box-shadow:0 0 0 3px rgba(var(--p-primary-500-rgb),.1)}.tree-search-input::placeholder{color:#94a3b8}.tree-search-clear{position:absolute;left:.55rem;width:1.65rem;height:1.65rem;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;color:#94a3b8;background:transparent;transition:all .2s ease}.tree-search-clear:hover{color:var(--p-primary-600);background:var(--p-primary-50)}.tree-search-clear i{font-size:.7rem}.dark .tree-back-btn{color:#cbd5e1}.dark .tree-back-btn:hover{color:var(--p-primary-300);background:rgba(var(--p-primary-500-rgb),.12)}.dark .tree-header-actions{background:#1f2937b8;border-color:#94a3b824}.dark .tree-icon-btn{color:#cbd5e1}.dark .tree-icon-btn:hover{color:#fff;background:var(--p-primary-600)}.dark .tree-search-icon{color:#64748b}.dark .tree-search-input{background:#1f2937bd;border-color:#94a3b829;color:#e5e7eb}.dark .tree-search-input:focus{background:#111827eb;border-color:rgba(var(--p-primary-500-rgb),.48)}.dark .tree-search-input::placeholder{color:#64748b}.dark .tree-search-clear{color:#94a3b8}.dark .tree-search-clear:hover{color:var(--p-primary-300);background:rgba(var(--p-primary-500-rgb),.12)}.search-match{background:linear-gradient(to left,rgba(var(--p-primary-500-rgb),.16),transparent)!important;color:var(--p-primary-700)!important;border-right:3px solid var(--p-primary-500)!important;box-shadow:inset 0 0 0 1px rgba(var(--p-primary-500-rgb),.08)}.search-match span{font-weight:800!important}.search-match i{color:var(--p-primary-600)!important}.dark .tree-toolbar{background:#111827b8;border-color:#ffffff14}.dark .tree-search-input{background:#1f2937cc;border-color:#94a3b82e;color:#e5e7eb}.dark .tree-search-input:focus{background:#111827f2}.dark .tree-search-clear{background:#374151e6;color:#cbd5e1}.dark .tree-action-btn{background:rgba(var(--p-primary-500-rgb),.12);color:var(--p-primary-300);border-color:rgba(var(--p-primary-500-rgb),.22)}.dark .tree-action-btn:hover{background:var(--p-primary-600);color:#fff}.dark .search-match{background:rgba(var(--p-primary-500-rgb),.18)!important;color:var(--p-primary-300)!important}\n"] }]
|
|
1442
1525
|
}], ctorParameters: () => [], propDecorators: { onResize: [{
|
|
1443
1526
|
type: HostListener,
|
|
1444
1527
|
args: ['window:resize']
|
|
@@ -1447,11 +1530,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
1447
1530
|
class AuthWrapperComponent {
|
|
1448
1531
|
constructor() { }
|
|
1449
1532
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthWrapperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1450
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.3", type: AuthWrapperComponent, isStandalone: true, selector: "abp-auth-wrapper", ngImport: i0, template: " <ng-content></ng-content>\n\n\n<!-- <div class=\"row\">\n <div class=\"mx-auto col col-md-5\">\n @if ((service.isMultiTenancyEnabled$ | async) && service.isTenantBoxVisible) {\n <abp-tenant-box\n *abpReplaceableTemplate=\"{ componentKey: service.tenantBoxKey }\"\n ></abp-tenant-box>\n }\n\n <div class=\"abp-account-container\">\n @if (service.enableLocalLogin$ | async) {\n <div class=\"card mt-3 shadow-sm rounded\">\n <div class=\"card-body p-5\">\n <ng-content></ng-content>\n </div>\n </div>\n } @else {\n <div class=\"alert alert-warning\">\n <strong>{{ 'AbpAccount::InvalidLoginRequest' | localize }}</strong>\n {{ 'AbpAccount::ThereAreNoLoginSchemesConfiguredForThisClient' | localize }}\n </div>\n }\n </div>\n </div>\n</div> -->\n" });
|
|
1533
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.3", type: AuthWrapperComponent, isStandalone: true, selector: "abp-auth-wrapper", ngImport: i0, template: " <ng-content></ng-content>\r\n\r\n\r\n<!-- <div class=\"row\">\r\n <div class=\"mx-auto col col-md-5\">\r\n @if ((service.isMultiTenancyEnabled$ | async) && service.isTenantBoxVisible) {\r\n <abp-tenant-box\r\n *abpReplaceableTemplate=\"{ componentKey: service.tenantBoxKey }\"\r\n ></abp-tenant-box>\r\n }\r\n\r\n <div class=\"abp-account-container\">\r\n @if (service.enableLocalLogin$ | async) {\r\n <div class=\"card mt-3 shadow-sm rounded\">\r\n <div class=\"card-body p-5\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"alert alert-warning\">\r\n <strong>{{ 'AbpAccount::InvalidLoginRequest' | localize }}</strong>\r\n {{ 'AbpAccount::ThereAreNoLoginSchemesConfiguredForThisClient' | localize }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n</div> -->\r\n" });
|
|
1451
1534
|
}
|
|
1452
1535
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthWrapperComponent, decorators: [{
|
|
1453
1536
|
type: Component,
|
|
1454
|
-
args: [{ standalone: true, imports: [], selector: 'abp-auth-wrapper', template: " <ng-content></ng-content>\n\n\n<!-- <div class=\"row\">\n <div class=\"mx-auto col col-md-5\">\n @if ((service.isMultiTenancyEnabled$ | async) && service.isTenantBoxVisible) {\n <abp-tenant-box\n *abpReplaceableTemplate=\"{ componentKey: service.tenantBoxKey }\"\n ></abp-tenant-box>\n }\n\n <div class=\"abp-account-container\">\n @if (service.enableLocalLogin$ | async) {\n <div class=\"card mt-3 shadow-sm rounded\">\n <div class=\"card-body p-5\">\n <ng-content></ng-content>\n </div>\n </div>\n } @else {\n <div class=\"alert alert-warning\">\n <strong>{{ 'AbpAccount::InvalidLoginRequest' | localize }}</strong>\n {{ 'AbpAccount::ThereAreNoLoginSchemesConfiguredForThisClient' | localize }}\n </div>\n }\n </div>\n </div>\n</div> -->\n" }]
|
|
1537
|
+
args: [{ standalone: true, imports: [], selector: 'abp-auth-wrapper', template: " <ng-content></ng-content>\r\n\r\n\r\n<!-- <div class=\"row\">\r\n <div class=\"mx-auto col col-md-5\">\r\n @if ((service.isMultiTenancyEnabled$ | async) && service.isTenantBoxVisible) {\r\n <abp-tenant-box\r\n *abpReplaceableTemplate=\"{ componentKey: service.tenantBoxKey }\"\r\n ></abp-tenant-box>\r\n }\r\n\r\n <div class=\"abp-account-container\">\r\n @if (service.enableLocalLogin$ | async) {\r\n <div class=\"card mt-3 shadow-sm rounded\">\r\n <div class=\"card-body p-5\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"alert alert-warning\">\r\n <strong>{{ 'AbpAccount::InvalidLoginRequest' | localize }}</strong>\r\n {{ 'AbpAccount::ThereAreNoLoginSchemesConfiguredForThisClient' | localize }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n</div> -->\r\n" }]
|
|
1455
1538
|
}], ctorParameters: () => [] });
|
|
1456
1539
|
|
|
1457
1540
|
class AccountLayoutComponent {
|
|
@@ -1466,11 +1549,11 @@ class AccountLayoutComponent {
|
|
|
1466
1549
|
// this.service.subscribeWindowSize();
|
|
1467
1550
|
}
|
|
1468
1551
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AccountLayoutComponent, deps: [{ token: LayoutService }], target: i0.ɵɵFactoryTarget.Component });
|
|
1469
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.3", type: AccountLayoutComponent, isStandalone: true, selector: "abp-layout-account", providers: [LayoutService, SubscriptionService], ngImport: i0, template: " <abp-auth-wrapper\n *abpReplaceableTemplate=\"{\n componentKey: authWrapperKey\n }\"\n >\n <router-outlet #outlet=\"outlet\"></router-outlet>\n </abp-auth-wrapper>\n", dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: AuthWrapperComponent, selector: "abp-auth-wrapper" }, { kind: "directive", type: ReplaceableTemplateDirective, selector: "[abpReplaceableTemplate]", inputs: ["abpReplaceableTemplate"] }] });
|
|
1552
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.3", type: AccountLayoutComponent, isStandalone: true, selector: "abp-layout-account", providers: [LayoutService, SubscriptionService], ngImport: i0, template: " <abp-auth-wrapper\r\n *abpReplaceableTemplate=\"{\r\n componentKey: authWrapperKey\r\n }\"\r\n >\r\n <router-outlet #outlet=\"outlet\"></router-outlet>\r\n </abp-auth-wrapper>\r\n", dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: AuthWrapperComponent, selector: "abp-auth-wrapper" }, { kind: "directive", type: ReplaceableTemplateDirective, selector: "[abpReplaceableTemplate]", inputs: ["abpReplaceableTemplate"] }] });
|
|
1470
1553
|
}
|
|
1471
1554
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AccountLayoutComponent, decorators: [{
|
|
1472
1555
|
type: Component,
|
|
1473
|
-
args: [{ standalone: true, imports: [RoutesComponent, NavItemsComponent, RouterOutlet, AuthWrapperComponent, ReplaceableTemplateDirective], selector: 'abp-layout-account', providers: [LayoutService, SubscriptionService], template: " <abp-auth-wrapper\n *abpReplaceableTemplate=\"{\n componentKey: authWrapperKey\n }\"\n >\n <router-outlet #outlet=\"outlet\"></router-outlet>\n </abp-auth-wrapper>\n" }]
|
|
1556
|
+
args: [{ standalone: true, imports: [RoutesComponent, NavItemsComponent, RouterOutlet, AuthWrapperComponent, ReplaceableTemplateDirective], selector: 'abp-layout-account', providers: [LayoutService, SubscriptionService], template: " <abp-auth-wrapper\r\n *abpReplaceableTemplate=\"{\r\n componentKey: authWrapperKey\r\n }\"\r\n >\r\n <router-outlet #outlet=\"outlet\"></router-outlet>\r\n </abp-auth-wrapper>\r\n" }]
|
|
1474
1557
|
}], ctorParameters: () => [{ type: LayoutService }] });
|
|
1475
1558
|
|
|
1476
1559
|
class ApplicationLayoutComponent {
|
|
@@ -1645,18 +1728,18 @@ class ApplicationLayoutComponent {
|
|
|
1645
1728
|
catch (error) {
|
|
1646
1729
|
}
|
|
1647
1730
|
}
|
|
1648
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ApplicationLayoutComponent, deps: [{ token: LayoutService }, { token: i0.Renderer2 }, { token: i2$
|
|
1649
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.3", type: ApplicationLayoutComponent, isStandalone: true, selector: "abp-layout-application", providers: [LayoutService, SubscriptionService], ngImport: i0, template: "\n\n<div class=\"flex h-screen overflow-hidden\">\n\n <!-- Sidebar stays fixed -->\n\n <app-routes\n *abpReplaceableTemplate=\"{\n componentKey: service.routesComponentKey,\n inputs: { smallScreen: { value: service.smallScreen } }\n }\"\n class=\"mb-2 md:mb-0\"\n ></app-routes>\n\n <!-- Main content scrolls -->\n <main class=\"flex-1 flex flex-col overflow-hidden\">\n\n <!-- Optional Topbar -->\n <!-- @if (showTopbar) { -->\n\n <app-nav-items\n *abpReplaceableTemplate=\"{\n componentKey: service.navItemsComponentKey\n }\"\n ></app-nav-items>\n\n <!-- p-6 space-y-6 -->\n <div class=\"flex-1 overflow-y-auto\">\n <router-outlet #outlet=\"outlet\"></router-outlet>\n </div>\n\n <!-- <app-footer></app-footer> -->\n\n </main>\n\n </div>\n\n", dependencies: [{ kind: "component", type: RoutesComponent, selector: "app-routes" }, { kind: "component", type: NavItemsComponent, selector: "app-nav-items" }, { kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "directive", type: ReplaceableTemplateDirective, selector: "[abpReplaceableTemplate]", inputs: ["abpReplaceableTemplate"] }], animations: [ /* slideFromBottom, */ /* appModuleAnimation() */] });
|
|
1731
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ApplicationLayoutComponent, deps: [{ token: LayoutService }, { token: i0.Renderer2 }, { token: i2$1.Router }, { token: i0.NgZone }, { token: i3$3.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
|
|
1732
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.3", type: ApplicationLayoutComponent, isStandalone: true, selector: "abp-layout-application", providers: [LayoutService, SubscriptionService], ngImport: i0, template: "\r\n\r\n<div class=\"flex h-screen overflow-hidden\">\r\n\r\n <!-- Sidebar stays fixed -->\r\n\r\n <app-routes\r\n *abpReplaceableTemplate=\"{\r\n componentKey: service.routesComponentKey,\r\n inputs: { smallScreen: { value: service.smallScreen } }\r\n }\"\r\n class=\"mb-2 md:mb-0\"\r\n ></app-routes>\r\n\r\n <!-- Main content scrolls -->\r\n <main class=\"flex-1 flex flex-col overflow-hidden\">\r\n\r\n <!-- Optional Topbar -->\r\n <!-- @if (showTopbar) { -->\r\n\r\n <app-nav-items\r\n *abpReplaceableTemplate=\"{\r\n componentKey: service.navItemsComponentKey\r\n }\"\r\n ></app-nav-items>\r\n\r\n <!-- p-6 space-y-6 -->\r\n <div class=\"flex-1 overflow-y-auto\">\r\n <router-outlet #outlet=\"outlet\"></router-outlet>\r\n </div>\r\n\r\n <!-- <app-footer></app-footer> -->\r\n\r\n </main>\r\n\r\n </div>\r\n\r\n", dependencies: [{ kind: "component", type: RoutesComponent, selector: "app-routes" }, { kind: "component", type: NavItemsComponent, selector: "app-nav-items" }, { kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "directive", type: ReplaceableTemplateDirective, selector: "[abpReplaceableTemplate]", inputs: ["abpReplaceableTemplate"] }], animations: [ /* slideFromBottom, */ /* appModuleAnimation() */] });
|
|
1650
1733
|
}
|
|
1651
1734
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ApplicationLayoutComponent, decorators: [{
|
|
1652
1735
|
type: Component,
|
|
1653
|
-
args: [{ standalone: true, imports: [RoutesComponent, NavItemsComponent, RouterOutlet, ReplaceableTemplateDirective], selector: 'abp-layout-application', animations: [ /* slideFromBottom, */ /* appModuleAnimation() */], providers: [LayoutService, SubscriptionService], template: "\n\n<div class=\"flex h-screen overflow-hidden\">\n\n <!-- Sidebar stays fixed -->\n\n <app-routes\n *abpReplaceableTemplate=\"{\n componentKey: service.routesComponentKey,\n inputs: { smallScreen: { value: service.smallScreen } }\n }\"\n class=\"mb-2 md:mb-0\"\n ></app-routes>\n\n <!-- Main content scrolls -->\n <main class=\"flex-1 flex flex-col overflow-hidden\">\n\n <!-- Optional Topbar -->\n <!-- @if (showTopbar) { -->\n\n <app-nav-items\n *abpReplaceableTemplate=\"{\n componentKey: service.navItemsComponentKey\n }\"\n ></app-nav-items>\n\n <!-- p-6 space-y-6 -->\n <div class=\"flex-1 overflow-y-auto\">\n <router-outlet #outlet=\"outlet\"></router-outlet>\n </div>\n\n <!-- <app-footer></app-footer> -->\n\n </main>\n\n </div>\n\n" }]
|
|
1654
|
-
}], ctorParameters: () => [{ type: LayoutService }, { type: i0.Renderer2 }, { type: i2$
|
|
1736
|
+
args: [{ standalone: true, imports: [RoutesComponent, NavItemsComponent, RouterOutlet, ReplaceableTemplateDirective], selector: 'abp-layout-application', animations: [ /* slideFromBottom, */ /* appModuleAnimation() */], providers: [LayoutService, SubscriptionService], template: "\r\n\r\n<div class=\"flex h-screen overflow-hidden\">\r\n\r\n <!-- Sidebar stays fixed -->\r\n\r\n <app-routes\r\n *abpReplaceableTemplate=\"{\r\n componentKey: service.routesComponentKey,\r\n inputs: { smallScreen: { value: service.smallScreen } }\r\n }\"\r\n class=\"mb-2 md:mb-0\"\r\n ></app-routes>\r\n\r\n <!-- Main content scrolls -->\r\n <main class=\"flex-1 flex flex-col overflow-hidden\">\r\n\r\n <!-- Optional Topbar -->\r\n <!-- @if (showTopbar) { -->\r\n\r\n <app-nav-items\r\n *abpReplaceableTemplate=\"{\r\n componentKey: service.navItemsComponentKey\r\n }\"\r\n ></app-nav-items>\r\n\r\n <!-- p-6 space-y-6 -->\r\n <div class=\"flex-1 overflow-y-auto\">\r\n <router-outlet #outlet=\"outlet\"></router-outlet>\r\n </div>\r\n\r\n <!-- <app-footer></app-footer> -->\r\n\r\n </main>\r\n\r\n </div>\r\n\r\n" }]
|
|
1737
|
+
}], ctorParameters: () => [{ type: LayoutService }, { type: i0.Renderer2 }, { type: i2$1.Router }, { type: i0.NgZone }, { type: i3$3.LocalizationService }] });
|
|
1655
1738
|
|
|
1656
1739
|
class EmptyLayoutComponent {
|
|
1657
1740
|
static type = eLayoutType.empty;
|
|
1658
1741
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmptyLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1659
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.3", type: EmptyLayoutComponent, isStandalone: true, selector: "abp-layout-empty", ngImport: i0, template: ` <router-outlet></router-outlet> `, isInline: true, dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2$
|
|
1742
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.3", type: EmptyLayoutComponent, isStandalone: true, selector: "abp-layout-empty", ngImport: i0, template: ` <router-outlet></router-outlet> `, isInline: true, dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2$1.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] });
|
|
1660
1743
|
}
|
|
1661
1744
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmptyLayoutComponent, decorators: [{
|
|
1662
1745
|
type: Component,
|