@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.
Files changed (97) hide show
  1. package/README.md +3 -0
  2. package/eslint.config.js +34 -0
  3. package/ng-package.json +7 -0
  4. package/package.json +19 -0
  5. package/project.json +29 -0
  6. package/src/index.ts +13 -0
  7. package/src/lib/app-accordion/app-accordion.component.html +15 -0
  8. package/src/lib/app-accordion/app-accordion.component.scss +0 -0
  9. package/src/lib/app-accordion/app-accordion.component.spec.ts +21 -0
  10. package/src/lib/app-accordion/app-accordion.component.ts +21 -0
  11. package/src/lib/app-accordion/index.ts +2 -0
  12. package/src/lib/app-button/app-button.component.html +13 -0
  13. package/src/lib/app-button/app-button.component.scss +0 -0
  14. package/src/lib/app-button/app-button.component.ts +28 -0
  15. package/src/lib/app-button/app-button.ts +15 -0
  16. package/src/lib/app-button/index.ts +2 -0
  17. package/src/lib/app-dropdown-menu/app-dropdown-menu.component.html +25 -0
  18. package/src/lib/app-dropdown-menu/app-dropdown-menu.component.scss +39 -0
  19. package/src/lib/app-dropdown-menu/app-dropdown-menu.component.spec.ts +21 -0
  20. package/src/lib/app-dropdown-menu/app-dropdown-menu.component.ts +43 -0
  21. package/src/lib/app-dropdown-menu/app-dropdown-menu.ts +17 -0
  22. package/src/lib/app-dropdown-menu/index.ts +2 -0
  23. package/src/lib/app-dropdown-menu/menu-popup.pipe.ts +18 -0
  24. package/src/lib/app-tabs/app-tab.interface.ts +26 -0
  25. package/src/lib/app-tabs/app-tabs.component.html +35 -0
  26. package/src/lib/app-tabs/app-tabs.component.scss +103 -0
  27. package/src/lib/app-tabs/app-tabs.component.spec.ts +21 -0
  28. package/src/lib/app-tabs/app-tabs.component.ts +48 -0
  29. package/src/lib/app-tabs/index.ts +2 -0
  30. package/src/lib/confirmation-dialog/confirmation-dialog.component.html +54 -0
  31. package/src/lib/confirmation-dialog/confirmation-dialog.component.scss +0 -0
  32. package/src/lib/confirmation-dialog/confirmation-dialog.component.spec.ts +22 -0
  33. package/src/lib/confirmation-dialog/confirmation-dialog.component.ts +51 -0
  34. package/src/lib/dynamic-form/dynamic-form.component.html +39 -0
  35. package/src/lib/dynamic-form/dynamic-form.component.scss +0 -0
  36. package/src/lib/dynamic-form/dynamic-form.component.spec.ts +21 -0
  37. package/src/lib/dynamic-form/dynamic-form.component.ts +29 -0
  38. package/src/lib/dynamic-form/dynamic-form.interface.ts +56 -0
  39. package/src/lib/form-components/@utils/form-utils.ts +12 -0
  40. package/src/lib/form-components/@utils/validations/error-keys.enum.ts +24 -0
  41. package/src/lib/form-components/@utils/validations/form-validation.service.ts +53 -0
  42. package/src/lib/form-components/@utils/validations/index.ts +3 -0
  43. package/src/lib/form-components/@utils/validations/validation-message.pipe.ts +24 -0
  44. package/src/lib/form-components/components/auto-complete/auto-complete.component.html +48 -0
  45. package/src/lib/form-components/components/auto-complete/auto-complete.component.scss +0 -0
  46. package/src/lib/form-components/components/auto-complete/auto-complete.component.spec.ts +21 -0
  47. package/src/lib/form-components/components/auto-complete/auto-complete.component.ts +48 -0
  48. package/src/lib/form-components/components/base-input.component.ts +41 -0
  49. package/src/lib/form-components/components/date-picker/date-picker.component.html +53 -0
  50. package/src/lib/form-components/components/date-picker/date-picker.component.scss +4 -0
  51. package/src/lib/form-components/components/date-picker/date-picker.component.spec.ts +23 -0
  52. package/src/lib/form-components/components/date-picker/date-picker.component.ts +45 -0
  53. package/src/lib/form-components/components/input/input.component.html +59 -0
  54. package/src/lib/form-components/components/input/input.component.scss +3 -0
  55. package/src/lib/form-components/components/input/input.component.spec.ts +21 -0
  56. package/src/lib/form-components/components/input/input.component.ts +32 -0
  57. package/src/lib/form-components/components/select/select.component.html +90 -0
  58. package/src/lib/form-components/components/select/select.component.scss +0 -0
  59. package/src/lib/form-components/components/select/select.component.spec.ts +21 -0
  60. package/src/lib/form-components/components/select/select.component.ts +51 -0
  61. package/src/lib/form-components/components/select-button/select-button.component.html +21 -0
  62. package/src/lib/form-components/components/select-button/select-button.component.scss +0 -0
  63. package/src/lib/form-components/components/select-button/select-button.component.spec.ts +21 -0
  64. package/src/lib/form-components/components/select-button/select-button.component.ts +22 -0
  65. package/src/lib/form-components/components/switcher/switch.component.html +5 -0
  66. package/src/lib/form-components/components/switcher/switch.component.scss +0 -0
  67. package/src/lib/form-components/components/switcher/switch.component.spec.ts +21 -0
  68. package/src/lib/form-components/components/switcher/switch.component.ts +25 -0
  69. package/src/lib/form-components/index.ts +9 -0
  70. package/src/lib/form-components/interfaces/index.ts +1 -0
  71. package/src/lib/form-components/interfaces/label-value.ts +4 -0
  72. package/src/lib/ico-moon-icon/ico-moon-icon.component.ts +23 -0
  73. package/src/lib/read-more/read-more.component.html +17 -0
  74. package/src/lib/read-more/read-more.component.scss +0 -0
  75. package/src/lib/read-more/read-more.component.spec.ts +21 -0
  76. package/src/lib/read-more/read-more.component.ts +21 -0
  77. package/src/lib/side-bar/side-bar.component.html +25 -0
  78. package/src/lib/side-bar/side-bar.component.scss +5 -0
  79. package/src/lib/side-bar/side-bar.component.spec.ts +21 -0
  80. package/src/lib/side-bar/side-bar.component.ts +32 -0
  81. package/src/lib/side-bar-dynamic/data-injector.pipe.ts +15 -0
  82. package/src/lib/side-bar-dynamic/dynamic-sidebar.service.ts +116 -0
  83. package/src/lib/side-bar-dynamic/side-bar-dynamic.component.html +51 -0
  84. package/src/lib/side-bar-dynamic/side-bar-dynamic.component.scss +5 -0
  85. package/src/lib/side-bar-dynamic/side-bar-dynamic.component.spec.ts +21 -0
  86. package/src/lib/side-bar-dynamic/side-bar-dynamic.component.ts +37 -0
  87. package/src/lib/side-bar-dynamic/side-bar-utils.ts +30 -0
  88. package/src/lib/side-bar-dynamic/sidebar-config.ts +48 -0
  89. package/src/lib/user-autocomplete-card/user-autocomplete-card.component.html +20 -0
  90. package/src/lib/user-autocomplete-card/user-autocomplete-card.component.scss +0 -0
  91. package/src/lib/user-autocomplete-card/user-autocomplete-card.component.spec.ts +21 -0
  92. package/src/lib/user-autocomplete-card/user-autocomplete-card.component.ts +21 -0
  93. package/src/lib/user-info/user-info.component.html +10 -0
  94. package/src/lib/user-info/user-info.component.ts +11 -0
  95. package/tsconfig.json +25 -0
  96. package/tsconfig.lib.json +12 -0
  97. package/tsconfig.lib.prod.json +9 -0
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # ui-components
2
+
3
+ This library was generated with [Nx](https://nx.dev).
@@ -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
+ ];
@@ -0,0 +1,7 @@
1
+ {
2
+ "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3
+ "dest": "../../dist/libs/ui-components",
4
+ "lib": {
5
+ "entryFile": "src/index.ts"
6
+ }
7
+ }
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>
@@ -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,2 @@
1
+ // export * from './app-button';
2
+ export * from './app-accordion.component';
@@ -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,2 @@
1
+ export * from './app-button';
2
+ export * from './app-button.component';
@@ -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,2 @@
1
+ export * from './app-dropdown-menu';
2
+ export * from './app-dropdown-menu.component';
@@ -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
+ }
@@ -0,0 +1,2 @@
1
+ export * from './app-tab.interface';
2
+ export * from './app-tabs.component';