@corp-products/ui-components 0.0.1
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.
- package/README.md +3 -0
- package/eslint.config.js +34 -0
- package/ng-package.json +7 -0
- package/package.json +19 -0
- package/project.json +29 -0
- package/src/index.ts +13 -0
- package/src/lib/app-accordion/app-accordion.component.html +15 -0
- package/src/lib/app-accordion/app-accordion.component.scss +0 -0
- package/src/lib/app-accordion/app-accordion.component.spec.ts +21 -0
- package/src/lib/app-accordion/app-accordion.component.ts +21 -0
- package/src/lib/app-accordion/index.ts +2 -0
- package/src/lib/app-button/app-button.component.html +13 -0
- package/src/lib/app-button/app-button.component.scss +0 -0
- package/src/lib/app-button/app-button.component.ts +28 -0
- package/src/lib/app-button/app-button.ts +15 -0
- package/src/lib/app-button/index.ts +2 -0
- package/src/lib/app-dropdown-menu/app-dropdown-menu.component.html +25 -0
- package/src/lib/app-dropdown-menu/app-dropdown-menu.component.scss +39 -0
- package/src/lib/app-dropdown-menu/app-dropdown-menu.component.spec.ts +21 -0
- package/src/lib/app-dropdown-menu/app-dropdown-menu.component.ts +43 -0
- package/src/lib/app-dropdown-menu/app-dropdown-menu.ts +17 -0
- package/src/lib/app-dropdown-menu/index.ts +2 -0
- package/src/lib/app-dropdown-menu/menu-popup.pipe.ts +18 -0
- package/src/lib/app-tabs/app-tab.interface.ts +26 -0
- package/src/lib/app-tabs/app-tabs.component.html +35 -0
- package/src/lib/app-tabs/app-tabs.component.scss +103 -0
- package/src/lib/app-tabs/app-tabs.component.spec.ts +21 -0
- package/src/lib/app-tabs/app-tabs.component.ts +48 -0
- package/src/lib/app-tabs/index.ts +2 -0
- package/src/lib/confirmation-dialog/confirmation-dialog.component.html +54 -0
- package/src/lib/confirmation-dialog/confirmation-dialog.component.scss +0 -0
- package/src/lib/confirmation-dialog/confirmation-dialog.component.spec.ts +22 -0
- package/src/lib/confirmation-dialog/confirmation-dialog.component.ts +51 -0
- package/src/lib/dynamic-form/dynamic-form.component.html +39 -0
- package/src/lib/dynamic-form/dynamic-form.component.scss +0 -0
- package/src/lib/dynamic-form/dynamic-form.component.spec.ts +21 -0
- package/src/lib/dynamic-form/dynamic-form.component.ts +29 -0
- package/src/lib/dynamic-form/dynamic-form.interface.ts +56 -0
- package/src/lib/form-components/@utils/form-utils.ts +12 -0
- package/src/lib/form-components/@utils/validations/error-keys.enum.ts +24 -0
- package/src/lib/form-components/@utils/validations/form-validation.service.ts +53 -0
- package/src/lib/form-components/@utils/validations/index.ts +3 -0
- package/src/lib/form-components/@utils/validations/validation-message.pipe.ts +24 -0
- package/src/lib/form-components/components/auto-complete/auto-complete.component.html +48 -0
- package/src/lib/form-components/components/auto-complete/auto-complete.component.scss +0 -0
- package/src/lib/form-components/components/auto-complete/auto-complete.component.spec.ts +21 -0
- package/src/lib/form-components/components/auto-complete/auto-complete.component.ts +48 -0
- package/src/lib/form-components/components/base-input.component.ts +41 -0
- package/src/lib/form-components/components/date-picker/date-picker.component.html +53 -0
- package/src/lib/form-components/components/date-picker/date-picker.component.scss +4 -0
- package/src/lib/form-components/components/date-picker/date-picker.component.spec.ts +23 -0
- package/src/lib/form-components/components/date-picker/date-picker.component.ts +45 -0
- package/src/lib/form-components/components/input/input.component.html +59 -0
- package/src/lib/form-components/components/input/input.component.scss +3 -0
- package/src/lib/form-components/components/input/input.component.spec.ts +21 -0
- package/src/lib/form-components/components/input/input.component.ts +32 -0
- package/src/lib/form-components/components/select/select.component.html +90 -0
- package/src/lib/form-components/components/select/select.component.scss +0 -0
- package/src/lib/form-components/components/select/select.component.spec.ts +21 -0
- package/src/lib/form-components/components/select/select.component.ts +51 -0
- package/src/lib/form-components/components/select-button/select-button.component.html +21 -0
- package/src/lib/form-components/components/select-button/select-button.component.scss +0 -0
- package/src/lib/form-components/components/select-button/select-button.component.spec.ts +21 -0
- package/src/lib/form-components/components/select-button/select-button.component.ts +22 -0
- package/src/lib/form-components/components/switcher/switch.component.html +5 -0
- package/src/lib/form-components/components/switcher/switch.component.scss +0 -0
- package/src/lib/form-components/components/switcher/switch.component.spec.ts +21 -0
- package/src/lib/form-components/components/switcher/switch.component.ts +25 -0
- package/src/lib/form-components/index.ts +9 -0
- package/src/lib/form-components/interfaces/index.ts +1 -0
- package/src/lib/form-components/interfaces/label-value.ts +4 -0
- package/src/lib/ico-moon-icon/ico-moon-icon.component.ts +23 -0
- package/src/lib/read-more/read-more.component.html +17 -0
- package/src/lib/read-more/read-more.component.scss +0 -0
- package/src/lib/read-more/read-more.component.spec.ts +21 -0
- package/src/lib/read-more/read-more.component.ts +21 -0
- package/src/lib/side-bar/side-bar.component.html +25 -0
- package/src/lib/side-bar/side-bar.component.scss +5 -0
- package/src/lib/side-bar/side-bar.component.spec.ts +21 -0
- package/src/lib/side-bar/side-bar.component.ts +32 -0
- package/src/lib/side-bar-dynamic/data-injector.pipe.ts +15 -0
- package/src/lib/side-bar-dynamic/dynamic-sidebar.service.ts +116 -0
- package/src/lib/side-bar-dynamic/side-bar-dynamic.component.html +51 -0
- package/src/lib/side-bar-dynamic/side-bar-dynamic.component.scss +5 -0
- package/src/lib/side-bar-dynamic/side-bar-dynamic.component.spec.ts +21 -0
- package/src/lib/side-bar-dynamic/side-bar-dynamic.component.ts +37 -0
- package/src/lib/side-bar-dynamic/side-bar-utils.ts +30 -0
- package/src/lib/side-bar-dynamic/sidebar-config.ts +48 -0
- package/src/lib/user-autocomplete-card/user-autocomplete-card.component.html +20 -0
- package/src/lib/user-autocomplete-card/user-autocomplete-card.component.scss +0 -0
- package/src/lib/user-autocomplete-card/user-autocomplete-card.component.spec.ts +21 -0
- package/src/lib/user-autocomplete-card/user-autocomplete-card.component.ts +21 -0
- package/src/lib/user-info/user-info.component.html +10 -0
- package/src/lib/user-info/user-info.component.ts +11 -0
- package/tsconfig.json +25 -0
- package/tsconfig.lib.json +12 -0
- package/tsconfig.lib.prod.json +9 -0
package/README.md
ADDED
package/eslint.config.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const nx = require('@nx/eslint-plugin');
|
|
2
|
+
const baseConfig = require('../../eslint.config.js');
|
|
3
|
+
|
|
4
|
+
module.exports = [
|
|
5
|
+
...baseConfig,
|
|
6
|
+
...nx.configs['flat/angular'],
|
|
7
|
+
...nx.configs['flat/angular-template'],
|
|
8
|
+
{
|
|
9
|
+
files: ['**/*.ts'],
|
|
10
|
+
rules: {
|
|
11
|
+
'@angular-eslint/directive-selector': [
|
|
12
|
+
'error',
|
|
13
|
+
{
|
|
14
|
+
type: 'attribute',
|
|
15
|
+
prefix: 'app',
|
|
16
|
+
style: 'camelCase',
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
'@angular-eslint/component-selector': [
|
|
20
|
+
'error',
|
|
21
|
+
{
|
|
22
|
+
type: 'element',
|
|
23
|
+
prefix: 'app',
|
|
24
|
+
style: 'kebab-case',
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
files: ['**/*.html'],
|
|
31
|
+
// Override or add rules here
|
|
32
|
+
rules: {},
|
|
33
|
+
},
|
|
34
|
+
];
|
package/ng-package.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@corp-products/ui-components",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"author": "shireen Omar",
|
|
5
|
+
"description": "shared UI components across our apps",
|
|
6
|
+
"peerDependencies": {
|
|
7
|
+
"@angular/common": "^18.2.0",
|
|
8
|
+
"@angular/core": "^18.2.0"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"angular",
|
|
12
|
+
"library"
|
|
13
|
+
],
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"sideEffects": false
|
|
19
|
+
}
|
package/project.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ui-components",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"sourceRoot": "libs/ui-components/src",
|
|
5
|
+
"prefix": "",
|
|
6
|
+
"projectType": "library",
|
|
7
|
+
"tags": [],
|
|
8
|
+
"targets": {
|
|
9
|
+
"build": {
|
|
10
|
+
"executor": "@nx/angular:package",
|
|
11
|
+
"outputs": ["{workspaceRoot}/dist/{projectRoot}"],
|
|
12
|
+
"options": {
|
|
13
|
+
"project": "libs/ui-components/ng-package.json"
|
|
14
|
+
},
|
|
15
|
+
"configurations": {
|
|
16
|
+
"production": {
|
|
17
|
+
"tsConfig": "libs/ui-components/tsconfig.lib.prod.json"
|
|
18
|
+
},
|
|
19
|
+
"development": {
|
|
20
|
+
"tsConfig": "libs/ui-components/tsconfig.lib.json"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"defaultConfiguration": "production"
|
|
24
|
+
},
|
|
25
|
+
"lint": {
|
|
26
|
+
"executor": "@nx/eslint:lint"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from './lib/app-button';
|
|
2
|
+
export * from './lib/app-tabs';
|
|
3
|
+
export * from './lib/app-dropdown-menu';
|
|
4
|
+
export * from './lib/side-bar/side-bar.component';
|
|
5
|
+
export * from './lib/ico-moon-icon/ico-moon-icon.component';
|
|
6
|
+
export * from './lib/user-info/user-info.component';
|
|
7
|
+
export * from './lib/confirmation-dialog/confirmation-dialog.component';
|
|
8
|
+
export * from './lib/read-more/read-more.component';
|
|
9
|
+
export * from './lib/app-accordion/app-accordion.component';
|
|
10
|
+
export * from './lib/dynamic-form/dynamic-form.interface';
|
|
11
|
+
export * from './lib/dynamic-form/dynamic-form.component';
|
|
12
|
+
export * from './lib/form-components';
|
|
13
|
+
export * from './lib/user-autocomplete-card/user-autocomplete-card.component';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<p-accordion value="0">
|
|
2
|
+
<p-accordion-panel value="0" [class.!border-0]="!accordionPanelBorder">
|
|
3
|
+
<p-accordion-header>
|
|
4
|
+
<span class="flex items-center gap-2 w-full">
|
|
5
|
+
<app-ico-moon-card [iconClass]="'text-[24px] text-secondary'" [iconName]="'font-icon-'+iconName" />
|
|
6
|
+
<span class="font-bold whitespace-nowrap">{{title}}</span>
|
|
7
|
+
</span>
|
|
8
|
+
</p-accordion-header>
|
|
9
|
+
<p-accordion-content>
|
|
10
|
+
<div [ngClass]="{'border-t-2 border-gray-light pt-2': contentBorderTop, }">
|
|
11
|
+
<ng-content></ng-content>
|
|
12
|
+
</div>
|
|
13
|
+
</p-accordion-content>
|
|
14
|
+
</p-accordion-panel>
|
|
15
|
+
</p-accordion>
|
|
File without changes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from "@angular/core/testing";
|
|
2
|
+
import { AppAccordionComponent } from "./app-accordion.component";
|
|
3
|
+
|
|
4
|
+
describe("HeaderCardComponent", () => {
|
|
5
|
+
let component: AppAccordionComponent;
|
|
6
|
+
let fixture: ComponentFixture<AppAccordionComponent>;
|
|
7
|
+
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
await TestBed.configureTestingModule({
|
|
10
|
+
imports: [AppAccordionComponent]
|
|
11
|
+
}).compileComponents();
|
|
12
|
+
|
|
13
|
+
fixture = TestBed.createComponent(AppAccordionComponent);
|
|
14
|
+
component = fixture.componentInstance;
|
|
15
|
+
fixture.detectChanges();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should create", () => {
|
|
19
|
+
expect(component).toBeTruthy();
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Component, Input } from "@angular/core";
|
|
2
|
+
import { CommonModule } from "@angular/common";
|
|
3
|
+
import { IcoMoonIconComponent } from '../ico-moon-icon/ico-moon-icon.component';
|
|
4
|
+
import { AccordionModule } from 'primeng/accordion';
|
|
5
|
+
import { DividerModule } from 'primeng/divider';
|
|
6
|
+
|
|
7
|
+
@Component({
|
|
8
|
+
selector: "app-accordion",
|
|
9
|
+
standalone: true,
|
|
10
|
+
imports: [CommonModule, DividerModule, AccordionModule, IcoMoonIconComponent],
|
|
11
|
+
templateUrl: "./app-accordion.component.html",
|
|
12
|
+
styleUrl: "./app-accordion.component.scss"
|
|
13
|
+
})
|
|
14
|
+
export class AppAccordionComponent {
|
|
15
|
+
@Input() iconName!: string;
|
|
16
|
+
@Input() iconClass!: string;
|
|
17
|
+
@Input() iconPathCount = 0;
|
|
18
|
+
@Input({required: true}) title!: string;
|
|
19
|
+
@Input() contentBorderTop: boolean = true;
|
|
20
|
+
@Input() accordionPanelBorder: boolean = true;
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<p-button
|
|
2
|
+
(click)="clickEmitter.emit()"
|
|
3
|
+
[class]="class"
|
|
4
|
+
[disabled]="disabled"
|
|
5
|
+
[iconPos]="iconPos"
|
|
6
|
+
[icon]="icon"
|
|
7
|
+
[label]="title"
|
|
8
|
+
[rounded]="rounded"
|
|
9
|
+
[severity]="style"
|
|
10
|
+
[styleClass]="'w-full'"
|
|
11
|
+
[text]="text"
|
|
12
|
+
[variant]="variant">
|
|
13
|
+
</p-button>
|
|
File without changes
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core';
|
|
3
|
+
import { RouterModule } from '@angular/router';
|
|
4
|
+
import { ButtonModule } from 'primeng/button';
|
|
5
|
+
import { AppButtonIconPos, AppButtonSeverity, AppButtonSize, AppButtonVariant } from './app-button';
|
|
6
|
+
|
|
7
|
+
@Component({
|
|
8
|
+
imports: [RouterModule, ButtonModule, CommonModule],
|
|
9
|
+
selector: 'app-button',
|
|
10
|
+
standalone: true,
|
|
11
|
+
encapsulation: ViewEncapsulation.None,
|
|
12
|
+
styleUrl: './app-button.component.scss',
|
|
13
|
+
templateUrl: './app-button.component.html',
|
|
14
|
+
})
|
|
15
|
+
export class AppButtonComponent {
|
|
16
|
+
@Input() title: string;
|
|
17
|
+
@Input() class: string;
|
|
18
|
+
@Input() icon: string;
|
|
19
|
+
@Input() size: AppButtonSize;
|
|
20
|
+
@Input() style: AppButtonSeverity;
|
|
21
|
+
@Input() iconPos: AppButtonIconPos;
|
|
22
|
+
@Input() variant: AppButtonVariant;
|
|
23
|
+
@Input() disabled = false;
|
|
24
|
+
@Input() text = false;
|
|
25
|
+
@Input() rounded = false;
|
|
26
|
+
|
|
27
|
+
@Output() clickEmitter = new EventEmitter<void>();
|
|
28
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type AppButtonSeverity =
|
|
2
|
+
| 'success'
|
|
3
|
+
| 'info'
|
|
4
|
+
| 'warn'
|
|
5
|
+
| 'danger'
|
|
6
|
+
| 'help'
|
|
7
|
+
| 'primary'
|
|
8
|
+
| 'secondary'
|
|
9
|
+
| 'contrast';
|
|
10
|
+
|
|
11
|
+
export type AppButtonSize = 'large' | 'small';
|
|
12
|
+
|
|
13
|
+
export type AppButtonIconPos = 'left' | 'right' | 'top' | 'bottom';
|
|
14
|
+
|
|
15
|
+
export type AppButtonVariant = 'outlined' | 'text' | undefined;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
@if (showMenu) {
|
|
2
|
+
<app-button (click)="op.toggle($event)" [class]="buttonClass"
|
|
3
|
+
[iconPos]="buttonIconPosition"
|
|
4
|
+
[icon]="buttonIcon" [title]="buttonTitle"
|
|
5
|
+
[style]="buttonStyle"/>
|
|
6
|
+
}
|
|
7
|
+
<p-popover #op [styleClass]="popupMenuStyle === 'white' ? 'white-menu' : 'purple-menu'">
|
|
8
|
+
<div class="flex flex-col gap-4 text-sm md:text-xs">
|
|
9
|
+
<ul>
|
|
10
|
+
@for (item of menuItems; track $index) {
|
|
11
|
+
@if (item.show) {
|
|
12
|
+
<li
|
|
13
|
+
[ngClass]="{'flex-row-reverse': item.iconPosition === 'right'}"
|
|
14
|
+
[class]="'flex justify-between min-w-[130px] gap-3 items-center cursor-pointer text-sm ' + (item.textColor | popupTextColorClass)"
|
|
15
|
+
(click)="onMenuItemClick(item)">
|
|
16
|
+
{{ item.title | translate }}
|
|
17
|
+
@if (item.icon) {
|
|
18
|
+
<i [class]="item.icon"></i>
|
|
19
|
+
}
|
|
20
|
+
</li>
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
</ul>
|
|
24
|
+
</div>
|
|
25
|
+
</p-popover>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
.p-popover.p-component {
|
|
2
|
+
box-shadow: none;
|
|
3
|
+
&:is(.purple-menu) {
|
|
4
|
+
@apply bg-primary text-white text-sm mt-2;
|
|
5
|
+
li:not(:last-child) {
|
|
6
|
+
@apply border-b-2 border-purple-700;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
&:is(.white-menu) {
|
|
10
|
+
li:not(:last-child) {
|
|
11
|
+
@apply border-b;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
border-radius: 3px;
|
|
15
|
+
margin-top: 13px;
|
|
16
|
+
&::before, &::after {
|
|
17
|
+
display: none;
|
|
18
|
+
}
|
|
19
|
+
.p-popover-content {
|
|
20
|
+
width: auto;
|
|
21
|
+
min-width: unset;
|
|
22
|
+
|
|
23
|
+
ul {
|
|
24
|
+
li {
|
|
25
|
+
@apply py-3;
|
|
26
|
+
&:hover {
|
|
27
|
+
opacity: 0.7;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
li:first-child {
|
|
31
|
+
@apply pt-0
|
|
32
|
+
}
|
|
33
|
+
li:last-child {
|
|
34
|
+
@apply pb-0
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
import { AppDropdownMenuComponent } from './app-dropdown-menu.component';
|
|
3
|
+
|
|
4
|
+
describe('AppDropdownMenuComponent', () => {
|
|
5
|
+
let component: AppDropdownMenuComponent;
|
|
6
|
+
let fixture: ComponentFixture<AppDropdownMenuComponent>;
|
|
7
|
+
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
await TestBed.configureTestingModule({
|
|
10
|
+
imports: [AppDropdownMenuComponent],
|
|
11
|
+
}).compileComponents();
|
|
12
|
+
|
|
13
|
+
fixture = TestBed.createComponent(AppDropdownMenuComponent);
|
|
14
|
+
component = fixture.componentInstance;
|
|
15
|
+
fixture.detectChanges();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should create', () => {
|
|
19
|
+
expect(component).toBeTruthy();
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {Component, inject, Input, OnInit, ViewEncapsulation} from '@angular/core';
|
|
2
|
+
import { AppButtonComponent } from '../app-button';
|
|
3
|
+
import { Popover } from 'primeng/popover';
|
|
4
|
+
import { DropdownMenuItem } from './app-dropdown-menu';
|
|
5
|
+
import {Router} from '@angular/router';
|
|
6
|
+
import {AppButtonIconPos, AppButtonSeverity} from '../app-button';
|
|
7
|
+
import { TranslateModule } from '@ngx-translate/core';
|
|
8
|
+
import {NgClass} from "@angular/common";
|
|
9
|
+
import {MenuPopupTextColorPipe} from "./menu-popup.pipe";
|
|
10
|
+
|
|
11
|
+
@Component({
|
|
12
|
+
selector: "app-dropdown-menu",
|
|
13
|
+
standalone: true,
|
|
14
|
+
imports: [AppButtonComponent, Popover, TranslateModule, NgClass, MenuPopupTextColorPipe],
|
|
15
|
+
templateUrl: "./app-dropdown-menu.component.html",
|
|
16
|
+
styleUrl: "./app-dropdown-menu.component.scss",
|
|
17
|
+
encapsulation: ViewEncapsulation.None
|
|
18
|
+
})
|
|
19
|
+
export class AppDropdownMenuComponent implements OnInit {
|
|
20
|
+
@Input({ required: true }) buttonTitle: string;
|
|
21
|
+
@Input({ required: true }) menuItems: DropdownMenuItem[] = [];
|
|
22
|
+
@Input() popupMenuStyle: "white" | "purple" = "purple";
|
|
23
|
+
@Input() buttonIcon = "font-icon-plus";
|
|
24
|
+
@Input() buttonClass: string;
|
|
25
|
+
@Input() buttonStyle: AppButtonSeverity;
|
|
26
|
+
@Input() buttonIconPosition: AppButtonIconPos = "left";
|
|
27
|
+
router = inject(Router);
|
|
28
|
+
|
|
29
|
+
showMenu: boolean;
|
|
30
|
+
|
|
31
|
+
ngOnInit() {
|
|
32
|
+
this.showMenu = this.menuItems.some((item) => {
|
|
33
|
+
return item.show;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
onMenuItemClick(item: DropdownMenuItem): void {
|
|
37
|
+
if (item.callback) {
|
|
38
|
+
item.callback();
|
|
39
|
+
} else if (item.routerLink) {
|
|
40
|
+
this.router.navigate(Array.isArray(item.routerLink) ? item.routerLink : [item.routerLink], { queryParams: item.queryParams || {} });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {Params} from "@angular/router";
|
|
2
|
+
import {AppButtonIconPos} from "../app-button";
|
|
3
|
+
|
|
4
|
+
export interface DropdownMenuItem {
|
|
5
|
+
title: string;
|
|
6
|
+
routerLink?: string;
|
|
7
|
+
queryParams?: Params;
|
|
8
|
+
callback?: () => void;
|
|
9
|
+
icon?: string;
|
|
10
|
+
show?: boolean;
|
|
11
|
+
// TODO: add type
|
|
12
|
+
permissionKey?: string;
|
|
13
|
+
permissionAction?: string;
|
|
14
|
+
iconPosition?: AppButtonIconPos;
|
|
15
|
+
textColor?: DropdownTextColor;
|
|
16
|
+
}
|
|
17
|
+
export type DropdownTextColor = 'white' | 'purple' | 'green';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Pipe, PipeTransform } from '@angular/core';
|
|
2
|
+
import {DropdownTextColor} from "./app-dropdown-menu";
|
|
3
|
+
|
|
4
|
+
@Pipe({
|
|
5
|
+
name: 'popupTextColorClass',
|
|
6
|
+
standalone: true,
|
|
7
|
+
pure: true
|
|
8
|
+
})
|
|
9
|
+
export class MenuPopupTextColorPipe implements PipeTransform {
|
|
10
|
+
transform(color?: DropdownTextColor): string {
|
|
11
|
+
switch (color) {
|
|
12
|
+
case 'white': return 'text-white';
|
|
13
|
+
case 'purple': return 'text-purple-500';
|
|
14
|
+
case 'green': return 'text-green-500';
|
|
15
|
+
default: return 'text-white';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { TemplateRef } from "@angular/core";
|
|
2
|
+
|
|
3
|
+
interface Tab {
|
|
4
|
+
title: string;
|
|
5
|
+
iconName?: string;
|
|
6
|
+
iconPathCount?: number;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
count?: number;
|
|
9
|
+
permissionKey?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface RoutedTab extends Tab {
|
|
13
|
+
link: string;
|
|
14
|
+
}
|
|
15
|
+
export interface TemplateTab extends Tab {
|
|
16
|
+
contentTemplate: TemplateRef<unknown>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
export type AppTabs = ({
|
|
21
|
+
isRouted: true;
|
|
22
|
+
items: RoutedTab[];
|
|
23
|
+
} | {
|
|
24
|
+
isRouted: false;
|
|
25
|
+
items: TemplateTab[];
|
|
26
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
@if (tabs && tabs.items.length) {
|
|
2
|
+
<div [class]="tabsStyle + (responsive ? ' full-width' : '') + ' tabs-container'">
|
|
3
|
+
<p-tabs [value]="activeTabIndex" scrollable>
|
|
4
|
+
<p-tablist>
|
|
5
|
+
|
|
6
|
+
@for (tab of tabs.items; let i = $index; track i) {
|
|
7
|
+
<p-tab [value]="i" [routerLink]="tabs.isRouted ? $any(tab).link : null" [disabled]="tab.disabled"
|
|
8
|
+
(click)="onTabChange(i)">
|
|
9
|
+
@if (tab.iconName) {
|
|
10
|
+
<app-ico-moon-card [iconClass]="'text-[17px]'" [iconName]="tab.iconName"
|
|
11
|
+
[iconPathCount]="tab.iconPathCount || 0"/>
|
|
12
|
+
}
|
|
13
|
+
<span>{{ tab.title | translate }} @if (tab.count) {
|
|
14
|
+
<span>({{ tab.count }})</span>
|
|
15
|
+
} </span>
|
|
16
|
+
</p-tab>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
</p-tablist>
|
|
20
|
+
|
|
21
|
+
<p-tabpanels>
|
|
22
|
+
@if (tabs.isRouted) {
|
|
23
|
+
<router-outlet></router-outlet>
|
|
24
|
+
} @else {
|
|
25
|
+
@for (tab of tabs.items; let i = $index; track i) {
|
|
26
|
+
<p-tabpanel [value]="i">
|
|
27
|
+
<ng-container [ngTemplateOutlet]="tab.contentTemplate"></ng-container>
|
|
28
|
+
</p-tabpanel>
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
</p-tabpanels>
|
|
33
|
+
</p-tabs>
|
|
34
|
+
</div>
|
|
35
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
.tabs-container {
|
|
2
|
+
&.full-width {
|
|
3
|
+
.p-tabs .p-tablist-tab-list .p-tab {
|
|
4
|
+
@apply flex-grow flex justify-center max-w-[50%];
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.p-tabs {
|
|
9
|
+
.p-tablist-tab-list {
|
|
10
|
+
@apply relative;
|
|
11
|
+
|
|
12
|
+
&:after {
|
|
13
|
+
@apply content-[''] w-full h-[3px] bg-purple-800/5 absolute bottom-0 right-0 z-[1];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.p-tab {
|
|
17
|
+
@apply text-sm text-gray-400 font-normal text-[16px] border-b-[4px] border-transparent z-[2];
|
|
18
|
+
|
|
19
|
+
&:not(.p-tab-active) {
|
|
20
|
+
app-ico-moon-card {
|
|
21
|
+
@apply grayscale;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.p-tablist-active-bar {
|
|
29
|
+
@apply hidden;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.p-tabpanels.p-component {
|
|
33
|
+
@apply mt-5 rounded-lg;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
&.basic {
|
|
38
|
+
.p-tabs {
|
|
39
|
+
.p-tablist-tab-list {
|
|
40
|
+
@apply bg-transparent;
|
|
41
|
+
|
|
42
|
+
.p-tab {
|
|
43
|
+
&.p-tab-active {
|
|
44
|
+
@apply text-primary border-primary;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
&.primary_light {
|
|
52
|
+
.p-tabs {
|
|
53
|
+
.p-tablist-tab-list {
|
|
54
|
+
.p-tab {
|
|
55
|
+
@apply rounded-t-lg text-[14px];
|
|
56
|
+
|
|
57
|
+
&.p-tab-active {
|
|
58
|
+
@apply bg-purple-800/5 font-semibold text-primary border-primary;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
&.primary {
|
|
66
|
+
.p-tabs {
|
|
67
|
+
.p-tablist-tab-list {
|
|
68
|
+
&:after {
|
|
69
|
+
@apply bg-purple-800/5;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.p-tab {
|
|
73
|
+
@apply rounded-t-lg text-[14px];
|
|
74
|
+
|
|
75
|
+
&.p-tab-active {
|
|
76
|
+
@apply bg-primary font-semibold text-white border-secondary;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
[dir='rtl'] {
|
|
85
|
+
.p-tabs .p-tablist{
|
|
86
|
+
.p-iconwrapper {
|
|
87
|
+
@apply rotate-180deg;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.p-tablist-next-button {
|
|
91
|
+
@apply right-auto left-0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.p-tablist-prev-button {
|
|
95
|
+
@apply right-0 left-auto;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// TODO : CHECK
|
|
101
|
+
// .p-tabpanels.p-component {
|
|
102
|
+
// @apply mt-5 rounded-[1.5rem];
|
|
103
|
+
// }
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
import { AppTabsComponent } from './app-tabs.component';
|
|
3
|
+
|
|
4
|
+
describe('AppTabsComponent', () => {
|
|
5
|
+
let component: AppTabsComponent;
|
|
6
|
+
let fixture: ComponentFixture<AppTabsComponent>;
|
|
7
|
+
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
await TestBed.configureTestingModule({
|
|
10
|
+
imports: [AppTabsComponent],
|
|
11
|
+
}).compileComponents();
|
|
12
|
+
|
|
13
|
+
fixture = TestBed.createComponent(AppTabsComponent);
|
|
14
|
+
component = fixture.componentInstance;
|
|
15
|
+
fixture.detectChanges();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should create', () => {
|
|
19
|
+
expect(component).toBeTruthy();
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { CommonModule } from "@angular/common";
|
|
2
|
+
import { Component, Input, OnInit, ViewEncapsulation } from "@angular/core";
|
|
3
|
+
import { TabsModule } from "primeng/tabs";
|
|
4
|
+
import { AppTabs } from "./app-tab.interface";
|
|
5
|
+
import { IcoMoonIconComponent } from "../ico-moon-icon/ico-moon-icon.component";
|
|
6
|
+
import { TranslateModule } from "@ngx-translate/core";
|
|
7
|
+
import { ActivatedRoute, NavigationEnd, Router, RouterLink, RouterOutlet } from "@angular/router";
|
|
8
|
+
import { filter } from "rxjs";
|
|
9
|
+
|
|
10
|
+
@Component({
|
|
11
|
+
selector: "app-tabs",
|
|
12
|
+
standalone: true,
|
|
13
|
+
encapsulation: ViewEncapsulation.None,
|
|
14
|
+
imports: [CommonModule, TabsModule, RouterLink, RouterOutlet, IcoMoonIconComponent, TranslateModule],
|
|
15
|
+
templateUrl: "./app-tabs.component.html",
|
|
16
|
+
styleUrl: "./app-tabs.component.scss"
|
|
17
|
+
})
|
|
18
|
+
export class AppTabsComponent implements OnInit {
|
|
19
|
+
@Input() tabs: AppTabs;
|
|
20
|
+
@Input() tabsStyle: "basic" | "primary_light" | "primary" = "basic";
|
|
21
|
+
@Input() responsive = false;
|
|
22
|
+
activeTabIndex = 0;
|
|
23
|
+
constructor(private route: ActivatedRoute, private router: Router) {}
|
|
24
|
+
|
|
25
|
+
ngOnInit(): void {
|
|
26
|
+
this.router.events.pipe(filter((event) => event instanceof NavigationEnd)).subscribe(() => {
|
|
27
|
+
this.updateActiveTab();
|
|
28
|
+
});
|
|
29
|
+
// to be refactor
|
|
30
|
+
this.updateActiveTab();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Updates the active tab index based on the current route
|
|
34
|
+
private updateActiveTab(): void {
|
|
35
|
+
if (!this.tabs.isRouted) return;
|
|
36
|
+
const currentUrl = this.router.url;
|
|
37
|
+
const matchingTabIndex = this.tabs.items.findIndex((tab) => currentUrl.includes(tab.link));
|
|
38
|
+
this.activeTabIndex = matchingTabIndex !== -1 ? matchingTabIndex : 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
onTabChange(index: number): void {
|
|
42
|
+
if (!this.tabs.isRouted) return;
|
|
43
|
+
const selectedTab = this.tabs.items[index];
|
|
44
|
+
if (selectedTab && !selectedTab.disabled) {
|
|
45
|
+
this.router.navigate([selectedTab.link], { relativeTo: this.route });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|