tailjng 0.0.60 → 0.0.62
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/cli/settings/components-list.js +7 -3
- package/cli/settings/header-generator.js +1 -1
- package/package.json +1 -1
- package/src/lib/components/card/card-complete/complete-card.component.html +1 -1
- package/src/lib/components/card/card-crud-complete/complete-crud-card.component.html +1 -1
- package/src/lib/components/filter/filter-complete/complete-filter.component.html +6 -1
- package/src/lib/components/filter/filter-complete/complete-filter.component.ts +3 -1
- package/src/lib/components/form/form-sidebar/sidebar-form.component.html +130 -97
- package/src/lib/components/form/form-sidebar/sidebar-form.component.ts +3 -2
- package/src/lib/components/input/input/input.component.css +35 -0
- package/src/lib/components/input/input/input.component.html +37 -27
- package/src/lib/components/input/input/input.component.ts +1 -0
- package/src/lib/components/menu/options-coach-menu/options-coach-menu.component.html +53 -0
- package/src/lib/components/menu/options-coach-menu/options-coach-menu.component.scss +0 -0
- package/src/lib/components/menu/options-coach-menu/options-coach-menu.component.ts +41 -0
- package/src/lib/components/paginator/paginator-complete/complete-paginator.component.html +8 -1
- package/src/lib/components/paginator/paginator-complete/complete-paginator.component.ts +2 -1
- package/src/lib/components/select/select-dropdown/dropdown-select.component.html +155 -83
- package/src/lib/components/select/select-dropdown/dropdown-select.component.ts +14 -2
- package/src/lib/components/select/select-multi-table/multi-table-select.component.html +2 -0
- package/src/lib/components/select/select-multi-table/multi-table-select.component.ts +12 -0
- package/src/lib/components/table/table-complete/complete-table.component.html +1 -1
- package/src/lib/components/table/table-complete/complete-table.component.scss +0 -5
- package/src/lib/components/table/table-crud-complete/complete-crud-table.component.html +9 -6
- package/src/lib/components/table/table-crud-complete/complete-crud-table.component.ts +3 -2
|
@@ -108,7 +108,7 @@ function getComponentList() {
|
|
|
108
108
|
},
|
|
109
109
|
'form-sidebar': {
|
|
110
110
|
path: "src/lib/components/form/form-sidebar",
|
|
111
|
-
dependencies: ["tooltip", "button", "checkbox-switch"],
|
|
111
|
+
dependencies: ["tooltip", "button", "checkbox-switch", "coach-mark"],
|
|
112
112
|
},
|
|
113
113
|
'paginator-complete': {
|
|
114
114
|
path: "src/lib/components/paginator/paginator-complete",
|
|
@@ -130,17 +130,21 @@ function getComponentList() {
|
|
|
130
130
|
path: "src/lib/components/menu/menu-options-table",
|
|
131
131
|
dependencies: ["button"],
|
|
132
132
|
},
|
|
133
|
+
'options-coach-menu': {
|
|
134
|
+
path: "src/lib/components/menu/options-coach-menu",
|
|
135
|
+
dependencies: ["button", "coach-mark"],
|
|
136
|
+
},
|
|
133
137
|
|
|
134
138
|
|
|
135
139
|
|
|
136
140
|
|
|
137
141
|
'table-crud-complete': {
|
|
138
142
|
path: "src/lib/components/table/table-crud-complete",
|
|
139
|
-
dependencies: ["button", "paginator-complete", "filter-complete", "checkbox-input", "
|
|
143
|
+
dependencies: ["button", "paginator-complete", "filter-complete", "checkbox-input", "options-coach-menu", "dialog", "viewer-image", "select-dropdown", "input"],
|
|
140
144
|
},
|
|
141
145
|
'table-complete': {
|
|
142
146
|
path: "src/lib/components/table/table-complete",
|
|
143
|
-
dependencies: ["button", "paginator-complete", "filter-complete", "checkbox-input", "
|
|
147
|
+
dependencies: ["button", "paginator-complete", "filter-complete", "checkbox-input", "options-coach-menu", "dialog", "viewer-image", "select-dropdown", "input"],
|
|
144
148
|
},
|
|
145
149
|
'theme-generator': {
|
|
146
150
|
path: "src/lib/components/theme-generator",
|
package/package.json
CHANGED
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
} @else if (displayData.length > 0) {
|
|
54
54
|
|
|
55
55
|
@if (itemTemplate) {
|
|
56
|
-
<div class="grid grid-cols-4
|
|
56
|
+
<div class="grid grid-cols-4 max-[1200px]:grid-cols-3 max-[950px]:grid-cols-2 max-[650px]:grid-cols-1 items-start gap-4 my-4">
|
|
57
57
|
@for (item of displayData; track trackById($index, item)) {
|
|
58
58
|
<div class="flex flex-col gap-3 rounded-xl border border-border dark:border-dark-border bg-white dark:bg-foreground shadow-sm hover:shadow-lg hover:border-primary/50 hover:dark:border-primary transition-all duration-300">
|
|
59
59
|
<ng-container
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
} @else if (displayData.length > 0) {
|
|
54
54
|
|
|
55
55
|
@if (itemTemplate) {
|
|
56
|
-
<div class="grid grid-cols-4
|
|
56
|
+
<div class="grid grid-cols-4 max-[1200px]:grid-cols-3 max-[950px]:grid-cols-2 max-[650px]:grid-cols-1 items-start gap-4 my-4">
|
|
57
57
|
@for (item of displayData; track trackById($index, item)) {
|
|
58
58
|
<div class="flex flex-col rounded-xl border border-border dark:border-dark-border bg-white dark:bg-foreground shadow-sm hover:shadow-lg hover:border-primary/50 hover:dark:border-primary transition-all duration-300">
|
|
59
59
|
<ng-container
|
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
type="text"
|
|
10
10
|
[(ngModel)]="searchQuery"
|
|
11
11
|
[placeholder]="searchPlaceholder"
|
|
12
|
-
class="input w-
|
|
12
|
+
class="input w-[250px] max-[768px]:w-full! h-[40px] max-[400px]:h-[35px] text-[12px] bg-background dark:bg-dark-background border border-border dark:border-dark-border text-black dark:text-white placeholder:text-muted-foreground/70 dark:placeholder:text-dark-muted-foreground/70 rounded px-3 py-2 pr-12 max-[400px]:pr-10 focus:outline-none focus:ring-2 focus:ring-primary dark:focus:ring-dark-primary transition duration-200 resize-y disabled:opacity-60 disabled:cursor-not-allowed"
|
|
13
|
+
[ngClass]="{
|
|
14
|
+
'bg-white dark:bg-foreground': !isbackground
|
|
15
|
+
}"
|
|
13
16
|
/>
|
|
14
17
|
|
|
15
18
|
<div
|
|
@@ -57,6 +60,7 @@
|
|
|
57
60
|
placeholder="Mostrar"
|
|
58
61
|
title="Mostrar elementos"
|
|
59
62
|
[options]="itemsPerPageOptions"
|
|
63
|
+
[ngClasses]="{ '!bg-white dark:!bg-foreground': !isbackground }"
|
|
60
64
|
/>
|
|
61
65
|
</div>
|
|
62
66
|
}
|
|
@@ -68,6 +72,7 @@
|
|
|
68
72
|
type="multi-table"
|
|
69
73
|
title="Seleccionar columnas"
|
|
70
74
|
[columns]="visibleColumns"
|
|
75
|
+
[ngClasses]="{ '!bg-white dark:!bg-foreground': !isbackground }"
|
|
71
76
|
/>
|
|
72
77
|
</div>
|
|
73
78
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Component, EventEmitter, Input, Output, OnDestroy, OnInit, ViewChild, ElementRef } from '@angular/core';
|
|
2
|
+
import { NgClass } from '@angular/common';
|
|
2
3
|
import { FormsModule } from '@angular/forms';
|
|
3
4
|
import { LucideAngularModule } from 'lucide-angular';
|
|
4
5
|
import { Subject, Subscription, debounceTime, filter, forkJoin } from 'rxjs';
|
|
@@ -12,7 +13,7 @@ import { JButtonComponent } from '../../button/button.component';
|
|
|
12
13
|
@Component({
|
|
13
14
|
selector: 'JFilter',
|
|
14
15
|
standalone: true,
|
|
15
|
-
imports: [LucideAngularModule, JDropdownSelectComponent, JMultiTableSelectComponent, JButtonComponent, JDialogComponent, FormsModule, JSwitchCheckboxComponent],
|
|
16
|
+
imports: [LucideAngularModule, JDropdownSelectComponent, JMultiTableSelectComponent, JButtonComponent, JDialogComponent, FormsModule, JSwitchCheckboxComponent, NgClass],
|
|
16
17
|
templateUrl: './complete-filter.component.html',
|
|
17
18
|
styleUrls: ['./complete-filter.component.scss'],
|
|
18
19
|
providers: [JDialogComponent]
|
|
@@ -35,6 +36,7 @@ export class JCompleteFilterComponent implements OnInit, OnDestroy {
|
|
|
35
36
|
@Input() isShowColumns: boolean = true;
|
|
36
37
|
@Input() mainEndpoint!: string;
|
|
37
38
|
@Input() data: any[] = [];
|
|
39
|
+
@Input() isbackground: boolean = false;
|
|
38
40
|
|
|
39
41
|
@Input() isItemsPerPage: boolean = true;
|
|
40
42
|
@Input() itemsPerPageOptions: number[] = [];
|
|
@@ -1,101 +1,134 @@
|
|
|
1
1
|
<section class="content_form">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
2
|
+
<!-- Overlay -->
|
|
3
|
+
@if (openForm) {
|
|
4
|
+
<div
|
|
5
|
+
onKeyPress
|
|
6
|
+
class="fixed top-0 left-0 w-full h-full bg-black/50 z-[999] transition duration-300"
|
|
7
|
+
(click)="canCloseOverlay ? onClose() : null"
|
|
8
|
+
></div>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
<!-- Sidebar personalizado -->
|
|
12
|
+
@if (openForm) {
|
|
13
|
+
<div
|
|
14
|
+
@sidebarTransition
|
|
15
|
+
class="fixed top-0 right-0 h-full max-w-full border border-border dark:border-dark-border rounded-tl-[15px] rounded-bl-[15px] text-white shadow-lg z-[999] flex flex-col"
|
|
16
|
+
[style]="style"
|
|
17
|
+
[ngClass]="bgColor"
|
|
18
|
+
[class.w-[22em]]="size === 'small'"
|
|
19
|
+
[class.w-[30em]]="size === 'medium'"
|
|
20
|
+
[class.w-[47em]]="size === 'large'"
|
|
21
|
+
[class.w-[65em]]="size === 'xlarge'"
|
|
22
|
+
>
|
|
23
|
+
<!-- Header -->
|
|
24
|
+
<div
|
|
25
|
+
class="flex p-2 pl-4 pr-4 justify-between items-center bg-primary dark:bg-dark-primary border-b border-border dark:border-dark-border rounded-tl-[15px] font-semibold text-2sm"
|
|
26
|
+
>
|
|
27
|
+
<div class="flex items-center gap-2">
|
|
28
|
+
<span>
|
|
29
|
+
{{
|
|
30
|
+
typeForm !== "none"
|
|
31
|
+
? typeForm === "create"
|
|
32
|
+
? "AGREGAR"
|
|
33
|
+
: "ACTUALIZAR"
|
|
34
|
+
: "REGISTROS"
|
|
35
|
+
}}
|
|
36
|
+
{{ typeForm !== "none" ? titleForm : "" }}
|
|
37
|
+
</span>
|
|
38
|
+
|
|
39
|
+
<JButton
|
|
40
|
+
jTooltip="Información"
|
|
41
|
+
jTooltipPosition="bottom"
|
|
42
|
+
jCoachMark
|
|
43
|
+
[coachContent]="coachContentChangePassword"
|
|
44
|
+
coachPosition="bottom"
|
|
45
|
+
coachTrigger="click"
|
|
46
|
+
[icon]="iconsService.icons.info"
|
|
47
|
+
classes="border-none shadow-none p-0 m-0 h-5 w-5 text-white"
|
|
48
|
+
/>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<ng-template #coachContentChangePassword>
|
|
52
|
+
<div class="text-[12px] leading-[15px]">
|
|
53
|
+
<span>
|
|
54
|
+
Las etiquetas con <span class="text-[10px]">✱</span> indican
|
|
55
|
+
campos requeridos.
|
|
56
|
+
</span>
|
|
57
|
+
<br />
|
|
58
|
+
<span>
|
|
59
|
+
<span class="text-red-600 dark:text-red-300">✱</span>
|
|
60
|
+
Obligatorio
|
|
61
|
+
</span>
|
|
62
|
+
<br />
|
|
63
|
+
<span>
|
|
64
|
+
<span class="text-blue-600 dark:text-blue-300">✱</span>
|
|
65
|
+
Condicionado
|
|
66
|
+
</span>
|
|
67
|
+
<br />
|
|
68
|
+
<span>
|
|
69
|
+
<span class="text-purple-600 dark:text-purple-300">✱</span>
|
|
70
|
+
Automático
|
|
71
|
+
</span>
|
|
72
|
+
</div>
|
|
73
|
+
</ng-template>
|
|
74
|
+
|
|
75
|
+
<div class="flex gap-2">
|
|
76
|
+
@for (cb of checkboxes; track $index) {
|
|
77
|
+
@if (cb.isVisible) {
|
|
78
|
+
<JSwitchCheckbox
|
|
79
|
+
onKeyPress
|
|
80
|
+
[title]="cb.title"
|
|
81
|
+
[isChecked]="cb.isChecked"
|
|
82
|
+
[isLoading]="cb.isLoading"
|
|
83
|
+
(click)="cb.onClick(!cb.isChecked, $index)"
|
|
84
|
+
/>
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<button
|
|
90
|
+
type="button"
|
|
91
|
+
(click)="onClose()"
|
|
92
|
+
class="p-2 rounded-full border border-border dark:border-dark-border text-white hover:bg-dark-background focus:outline-none cursor-pointer"
|
|
18
93
|
>
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
[jTooltipOffsetY]="-20"
|
|
31
|
-
>
|
|
32
|
-
<lucide-icon [name]="iconsService.icons.info" [size]="15"></lucide-icon>
|
|
33
|
-
</div>
|
|
34
|
-
</div>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<ng-template #tooltipContentChangePassword>
|
|
38
|
-
<div class="text-[12px] leading-[15px]">
|
|
39
|
-
<span>Las etiquetas con ✱ indican campos requeridos.</span> <br>
|
|
40
|
-
<span><span class="text-red-600 dark:text-red-300">✱</span> Obligatorio</span> <br>
|
|
41
|
-
<span><span class="text-blue-600 dark:text-blue-300">✱</span> Condicionado</span> <br>
|
|
42
|
-
<span><span class="text-purple-600 dark:text-purple-300">✱</span> Automático</span> <br>
|
|
43
|
-
</div>
|
|
44
|
-
</ng-template>
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
<div class="flex gap-2">
|
|
48
|
-
@for (cb of checkboxes; track $index) {
|
|
49
|
-
@if (cb.isVisible) {
|
|
50
|
-
<JSwitchCheckbox onKeyPress
|
|
51
|
-
[title]="cb.title"
|
|
52
|
-
[isChecked]="cb.isChecked"
|
|
53
|
-
[isLoading]="cb.isLoading"
|
|
54
|
-
(click)="cb.onClick(!cb.isChecked, $index)"
|
|
55
|
-
/>
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
</div>
|
|
59
|
-
|
|
60
|
-
<button type="button" (click)="onClose()" class="p-2 rounded-full border border-border dark:border-dark-border text-white hover:bg-dark-background focus:outline-none cursor-pointer">
|
|
61
|
-
<lucide-icon [name]="iconsService.icons.close" size="16"></lucide-icon>
|
|
62
|
-
</button>
|
|
63
|
-
</div>
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
<!-- Content -->
|
|
67
|
-
<div class="p-4 flex-1 overflow-x-hidden overflow-y-auto scroll-element">
|
|
68
|
-
@if (formTemplate) {
|
|
69
|
-
<ng-container [ngTemplateOutlet]="formTemplate"></ng-container>
|
|
70
|
-
}
|
|
71
|
-
</div>
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
<!-- Footer -->
|
|
75
|
-
@if (typeForm !== 'none') {
|
|
76
|
-
<div class="p-4 border-t border-border dark:border-dark-border rounded-bl-[15px] flex justify-center gap-3">
|
|
77
|
-
|
|
78
|
-
<JButton
|
|
79
|
-
type="submit"
|
|
80
|
-
(clicked)="onSubmit()"
|
|
81
|
-
classes="primary"
|
|
82
|
-
[icon]="iconsService.icons.save"
|
|
83
|
-
[isLoading]="isLoading"
|
|
84
|
-
>
|
|
85
|
-
{{typeForm === 'create' ? 'AGREGAR' : 'ACTUALIZAR'}}
|
|
86
|
-
</JButton>
|
|
87
|
-
|
|
88
|
-
<JButton
|
|
89
|
-
type="button"
|
|
90
|
-
(clicked)="onClose()"
|
|
91
|
-
classes="secondary"
|
|
92
|
-
[icon]="iconsService.icons.error"
|
|
93
|
-
text="CANCELAR"
|
|
94
|
-
/>
|
|
95
|
-
|
|
96
|
-
</div>
|
|
94
|
+
<lucide-icon
|
|
95
|
+
[name]="iconsService.icons.close"
|
|
96
|
+
size="16"
|
|
97
|
+
></lucide-icon>
|
|
98
|
+
</button>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<!-- Content -->
|
|
102
|
+
<div class="p-4 flex-1 overflow-x-hidden overflow-y-auto scroll-element">
|
|
103
|
+
@if (formTemplate) {
|
|
104
|
+
<ng-container [ngTemplateOutlet]="formTemplate"></ng-container>
|
|
97
105
|
}
|
|
98
|
-
|
|
99
|
-
}
|
|
106
|
+
</div>
|
|
100
107
|
|
|
101
|
-
|
|
108
|
+
<!-- Footer -->
|
|
109
|
+
@if (typeForm !== "none") {
|
|
110
|
+
<div
|
|
111
|
+
class="p-4 border-t border-border dark:border-dark-border rounded-bl-[15px] flex justify-center gap-3"
|
|
112
|
+
>
|
|
113
|
+
<JButton
|
|
114
|
+
type="submit"
|
|
115
|
+
(clicked)="onSubmit()"
|
|
116
|
+
classes="primary"
|
|
117
|
+
[icon]="iconsService.icons.save"
|
|
118
|
+
[isLoading]="isLoading"
|
|
119
|
+
>
|
|
120
|
+
{{ typeForm === "create" ? "AGREGAR" : "ACTUALIZAR" }}
|
|
121
|
+
</JButton>
|
|
122
|
+
|
|
123
|
+
<JButton
|
|
124
|
+
type="button"
|
|
125
|
+
(clicked)="onClose()"
|
|
126
|
+
classes="secondary"
|
|
127
|
+
[icon]="iconsService.icons.error"
|
|
128
|
+
text="CANCELAR"
|
|
129
|
+
/>
|
|
130
|
+
</div>
|
|
131
|
+
}
|
|
132
|
+
</div>
|
|
133
|
+
}
|
|
134
|
+
</section>
|
|
@@ -7,11 +7,12 @@ import { DynamicCheckbox, FormType, JIconsService } from 'tailjng';
|
|
|
7
7
|
import { JTooltipDirective } from '../../tooltip/tooltip.directive';
|
|
8
8
|
import { JButtonComponent } from '../../button/button.component';
|
|
9
9
|
import { JSwitchCheckboxComponent } from '../../checkbox/checkbox-switch/switch-checkbox.component';
|
|
10
|
+
import { JCoachMarkDirective } from '../../coach-mark/coach-mark.directive';
|
|
10
11
|
|
|
11
12
|
@Component({
|
|
12
13
|
selector: 'JSidebarForm',
|
|
13
14
|
standalone: true,
|
|
14
|
-
imports: [LucideAngularModule, JButtonComponent, JTooltipDirective, ReactiveFormsModule, FormsModule, CommonModule, JSwitchCheckboxComponent],
|
|
15
|
+
imports: [LucideAngularModule, JButtonComponent, JTooltipDirective, ReactiveFormsModule, FormsModule, CommonModule, JSwitchCheckboxComponent, JCoachMarkDirective],
|
|
15
16
|
templateUrl: './sidebar-form.component.html',
|
|
16
17
|
styleUrl: './sidebar-form.component.scss',
|
|
17
18
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
@@ -61,4 +62,4 @@ export class JSidebarFormComponent {
|
|
|
61
62
|
this.onClose();
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
|
-
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
@media (max-width: 400px) {
|
|
2
|
+
.input-container {
|
|
3
|
+
width: 100%;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
input[type="date"] {
|
|
7
|
+
appearance: none !important;
|
|
8
|
+
-webkit-appearance: none !important;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
input[type="date"]::-webkit-calendar-picker-indicator {
|
|
12
|
+
opacity: 0 !important;
|
|
13
|
+
display: none !important;
|
|
14
|
+
-webkit-appearance: none !important;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
input[type="date"]:not(:valid) {
|
|
18
|
+
color: transparent !important;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
input[type="date"]:not(:valid)::before {
|
|
22
|
+
content: attr(placeholder) !important;
|
|
23
|
+
color: rgb(148 163 184) !important;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.date-fake-placeholder {
|
|
28
|
+
display: none;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@media (pointer: coarse) {
|
|
32
|
+
.date-fake-placeholder {
|
|
33
|
+
display: block;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -1,29 +1,39 @@
|
|
|
1
1
|
<div class="relative w-full">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
[required]="required"
|
|
10
|
-
[disabled]="isDisabled"
|
|
11
|
-
(blur)="onTouched()"
|
|
12
|
-
[ngClass]="combinedNgClass"
|
|
13
|
-
[class]="classes"
|
|
14
|
-
class="input w-full h-[40px] max-[400px]:h-[35px] text-[12px] bg-background dark:bg-dark-background border border-border dark:border-dark-border text-black dark:text-white placeholder:text-muted-foreground/70 dark:placeholder:text-dark-muted-foreground/70 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary dark:focus:ring-dark-primary transition duration-200 resize-y disabled:opacity-60 disabled:cursor-not-allowed"
|
|
15
|
-
/>
|
|
2
|
+
@if (type === 'date' && !value && placeholder) {
|
|
3
|
+
<span
|
|
4
|
+
class="date-fake-placeholder pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-[12px] text-muted-foreground/70 dark:text-dark-muted-foreground/70 z-[1]"
|
|
5
|
+
>
|
|
6
|
+
{{ placeholder }}
|
|
7
|
+
</span>
|
|
8
|
+
}
|
|
16
9
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
10
|
+
<input
|
|
11
|
+
[type]="type"
|
|
12
|
+
[id]="id"
|
|
13
|
+
[name]="name ?? ''"
|
|
14
|
+
[placeholder]="placeholder"
|
|
15
|
+
[value]="value"
|
|
16
|
+
(input)="onInput($event)"
|
|
17
|
+
[required]="required"
|
|
18
|
+
[disabled]="isDisabled"
|
|
19
|
+
[readonly]="isReadonly"
|
|
20
|
+
(blur)="onTouched()"
|
|
21
|
+
[ngClass]="combinedNgClass"
|
|
22
|
+
[class]="classes"
|
|
23
|
+
class="input w-full h-[40px] max-[400px]:h-[35px] text-[12px] bg-background dark:bg-dark-background border border-border dark:border-dark-border text-black dark:text-white placeholder:text-muted-foreground/70 dark:placeholder:text-dark-muted-foreground/70 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary dark:focus:ring-dark-primary transition duration-200 resize-y disabled:opacity-60 disabled:cursor-not-allowed"
|
|
24
|
+
/>
|
|
25
|
+
|
|
26
|
+
@if (value && clearButton) {
|
|
27
|
+
<button
|
|
28
|
+
type="button"
|
|
29
|
+
class="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 text-gray-400 hover:text-gray-500 pr-1 mr-1 text-gray-400 hover:text-gray-600 focus:outline-none cursor-pointer"
|
|
30
|
+
(click)="clearInput()"
|
|
31
|
+
[disabled]="isDisabled"
|
|
32
|
+
[ngClass]="{
|
|
33
|
+
'cursor-not-allowed opacity-50': isDisabled,
|
|
34
|
+
}"
|
|
35
|
+
>
|
|
36
|
+
<lucide-icon [name]="iconsService.icons.close" class="w-4 h-4" />
|
|
37
|
+
</button>
|
|
38
|
+
}
|
|
39
|
+
</div>
|
|
@@ -26,6 +26,7 @@ export class JInputComponent implements ControlValueAccessor {
|
|
|
26
26
|
@Input() placeholder: string = '';
|
|
27
27
|
|
|
28
28
|
@Input() isDisabled: boolean = false;
|
|
29
|
+
@Input() isReadonly: boolean = false;
|
|
29
30
|
@Input() required: boolean = false;
|
|
30
31
|
@Input() clearButton: boolean = false;
|
|
31
32
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<div class="relative isolate">
|
|
2
|
+
<JButton
|
|
3
|
+
onKeyPress
|
|
4
|
+
jCoachMark
|
|
5
|
+
[contentTemplate]="customTemplateActions"
|
|
6
|
+
[isDescriptionFormatted]="true"
|
|
7
|
+
coachPosition="bottom-left"
|
|
8
|
+
coachTrigger="click"
|
|
9
|
+
[coachMaxWidth]="'170px'"
|
|
10
|
+
[coachSpotlight]="false"
|
|
11
|
+
[icon]="iconsService.icons.ellipsisVertical"
|
|
12
|
+
[iconSize]="20"
|
|
13
|
+
classes="secondary w-[35px] h-[35px] rounded-full"
|
|
14
|
+
(clicked)="handleClickGeneral()"
|
|
15
|
+
/>
|
|
16
|
+
|
|
17
|
+
<ng-template #customTemplateActions>
|
|
18
|
+
<div class="flex flex-col gap-2">
|
|
19
|
+
@if (optionsTable.length > 0) {
|
|
20
|
+
@for (option of optionsTable; track $index) {
|
|
21
|
+
@if (getIsVisible(option, group)) {
|
|
22
|
+
<div
|
|
23
|
+
class="w-full hover:bg-primary/10 dark:hover:bg-dark-primary/10 text-[10px]"
|
|
24
|
+
>
|
|
25
|
+
<JButton
|
|
26
|
+
onKeyPress
|
|
27
|
+
[icon]="getIcon(option.icon, group)"
|
|
28
|
+
[iconSize]="20"
|
|
29
|
+
(clicked)="handleClick(option, group)"
|
|
30
|
+
[tooltip]="getTooltip(option.tooltip ?? '', group)"
|
|
31
|
+
[tooltipPosition]="option.tooltipPosition ?? 'top'"
|
|
32
|
+
[disabled]="getDisabled(option, group)"
|
|
33
|
+
[isLoading]="false"
|
|
34
|
+
[classes]="
|
|
35
|
+
'w-full text-left justify-start ' + (option.classes ?? '')
|
|
36
|
+
"
|
|
37
|
+
[ngClasses]="mergeNgClasses(option.ngClass, group)"
|
|
38
|
+
>
|
|
39
|
+
{{ getTooltip(option.text ?? "", group) }}
|
|
40
|
+
</JButton>
|
|
41
|
+
</div>
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} @else {
|
|
45
|
+
<div
|
|
46
|
+
class="text-center text-gray-500 dark:text-dark-text-secondary text-xs"
|
|
47
|
+
>
|
|
48
|
+
No hay opciones disponibles
|
|
49
|
+
</div>
|
|
50
|
+
}
|
|
51
|
+
</div>
|
|
52
|
+
</ng-template>
|
|
53
|
+
</div>
|
|
File without changes
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter, ElementRef, OnDestroy, ViewChild, AfterViewInit, Renderer2 } from '@angular/core';
|
|
2
|
+
import { LucideAngularModule } from 'lucide-angular';
|
|
3
|
+
import { JButtonComponent } from '../../button/button.component';
|
|
4
|
+
import { JIconsService } from 'tailjng';
|
|
5
|
+
import { JCoachMarkDirective } from '../../coach-mark/coach-mark.directive';
|
|
6
|
+
|
|
7
|
+
@Component({
|
|
8
|
+
selector: 'JOptionsCoachMenu',
|
|
9
|
+
imports: [LucideAngularModule, JButtonComponent, JCoachMarkDirective],
|
|
10
|
+
templateUrl: './options-coach-menu.component.html',
|
|
11
|
+
styleUrl: './options-coach-menu.component.scss'
|
|
12
|
+
})
|
|
13
|
+
export class JOptionsCoachMenuComponent {
|
|
14
|
+
|
|
15
|
+
@Input() optionsTable: any[] = [];
|
|
16
|
+
@Input() group: any;
|
|
17
|
+
@Input() rowId: string | number | null = null;
|
|
18
|
+
|
|
19
|
+
@Input() getIcon: (icon: any, group: any) => any = () => null;
|
|
20
|
+
@Input() getTooltip: (tooltip: string, group: any) => string = () => '';
|
|
21
|
+
@Input() getDisabled: (option: any, group: any) => boolean = () => false;
|
|
22
|
+
@Input() getIsVisible: (option: any, group: any) => boolean = () => true;
|
|
23
|
+
@Input() mergeNgClasses: (ngClass: any, group: any) => any = () => '';
|
|
24
|
+
@Input() isAditionalButtonLoading: (type: string, id: any) => boolean = () => false;
|
|
25
|
+
|
|
26
|
+
@Output() clicked = new EventEmitter<{ option: any; group: any }>();
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
constructor(
|
|
30
|
+
public readonly iconsService: JIconsService,
|
|
31
|
+
) { }
|
|
32
|
+
|
|
33
|
+
handleClick(option: any, group: any): void {
|
|
34
|
+
this.clicked.emit({ option, group });
|
|
35
|
+
this.handleClickGeneral();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
handleClickGeneral(): void {
|
|
39
|
+
document.body.click();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
[isLoadingText]="false"
|
|
18
18
|
classes="secondary h-[35px]"
|
|
19
19
|
[class.disabled]="currentPage === 1 || isLoading"
|
|
20
|
+
[ngClasses]="{ '!bg-white dark:!bg-foreground': !isbackground }"
|
|
20
21
|
/>
|
|
21
22
|
|
|
22
23
|
<!-- Previous page -->
|
|
@@ -29,6 +30,7 @@
|
|
|
29
30
|
[isLoading]="isButtonLoading('prev')"
|
|
30
31
|
[isLoadingText]="false"
|
|
31
32
|
[class.disabled]="currentPage === 1 || isLoading"
|
|
33
|
+
[ngClasses]="{ '!bg-white dark:!bg-foreground': !isbackground }"
|
|
32
34
|
/>
|
|
33
35
|
|
|
34
36
|
<!-- Page numbers -->
|
|
@@ -41,7 +43,10 @@
|
|
|
41
43
|
[disabled]="currentPage === page || isLoading"
|
|
42
44
|
[isLoading]="isButtonLoading(page)"
|
|
43
45
|
[isLoadingText]="false"
|
|
44
|
-
[ngClasses]="{
|
|
46
|
+
[ngClasses]="{
|
|
47
|
+
'primary' : currentPage === page,
|
|
48
|
+
'!bg-white dark:!bg-foreground': !isbackground && currentPage !== page,
|
|
49
|
+
}"
|
|
45
50
|
/>
|
|
46
51
|
}
|
|
47
52
|
|
|
@@ -55,6 +60,7 @@
|
|
|
55
60
|
[isLoading]="isButtonLoading('next')"
|
|
56
61
|
[isLoadingText]="false"
|
|
57
62
|
[class.disabled]="currentPage === totalPages || isLoading"
|
|
63
|
+
[ngClasses]="{ '!bg-white dark:!bg-foreground': !isbackground }"
|
|
58
64
|
/>
|
|
59
65
|
|
|
60
66
|
<!-- Last page -->
|
|
@@ -67,6 +73,7 @@
|
|
|
67
73
|
[isLoading]="isButtonLoading('last')"
|
|
68
74
|
[isLoadingText]="false"
|
|
69
75
|
[class.disabled]="currentPage === totalPages || isLoading"
|
|
76
|
+
[ngClasses]="{ '!bg-white dark:!bg-foreground': !isbackground }"
|
|
70
77
|
/>
|
|
71
78
|
|
|
72
79
|
</div>
|
|
@@ -24,6 +24,7 @@ export class JCompletePaginatorComponent {
|
|
|
24
24
|
@Input() itemsPerPage = this.itemsPerPageOptions[0];
|
|
25
25
|
@Input() totalItems = 0;
|
|
26
26
|
|
|
27
|
+
@Input() isbackground = false;
|
|
27
28
|
|
|
28
29
|
@Input() isLoading = false;
|
|
29
30
|
|
|
@@ -112,5 +113,5 @@ export class JCompletePaginatorComponent {
|
|
|
112
113
|
isButtonLoading(button: 'first' | 'prev' | 'next' | 'last' | number): boolean {
|
|
113
114
|
return this.isLoading && this.loadingButton === button;
|
|
114
115
|
}
|
|
115
|
-
|
|
116
|
+
|
|
116
117
|
}
|
|
@@ -1,94 +1,166 @@
|
|
|
1
1
|
<div class="relative w-full h-full">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
2
|
+
<div #selectButton class="w-auto">
|
|
3
|
+
<button
|
|
4
|
+
type="button"
|
|
5
|
+
[disabled]="isDisabled || isLoading"
|
|
6
|
+
(click)="toggleColumnSelector()"
|
|
7
|
+
[class]="
|
|
8
|
+
'flex w-full h-[40px] max-[400px]:h-[35px] text-[12px] items-center justify-between px-3 py-2 text-sm bg-background dark:bg-dark-background border border-border dark:border-dark-border rounded focus:outline-none focus:ring-2 focus:ring-primary select-none' +
|
|
9
|
+
' ' +
|
|
10
|
+
classes
|
|
11
|
+
"
|
|
12
|
+
[ngClass]="getButtonNgClass()"
|
|
13
|
+
>
|
|
14
|
+
<span
|
|
15
|
+
class="truncate text-black dark:text-white"
|
|
16
|
+
[ngClass]="{
|
|
17
|
+
'opacity-70 text-muted-foreground dark:text-dark-muted-foreground':
|
|
18
|
+
selectedValue === null,
|
|
19
|
+
}"
|
|
20
|
+
>{{ selectedLabel }}</span
|
|
21
|
+
>
|
|
22
|
+
|
|
23
|
+
<div class="flex items-center">
|
|
24
|
+
@if (showClear && selectedValue !== null) {
|
|
25
|
+
<button
|
|
26
|
+
type="button"
|
|
27
|
+
(click)="clearSelection($event)"
|
|
28
|
+
class="pr-1 mr-1 text-gray-400 hover:text-gray-600 focus:outline-none cursor-pointer"
|
|
29
|
+
>
|
|
30
|
+
<lucide-icon
|
|
31
|
+
[name]="iconsService.icons.close"
|
|
32
|
+
size="14"
|
|
33
|
+
></lucide-icon>
|
|
34
|
+
</button>
|
|
35
|
+
}
|
|
36
|
+
@if (!isLoading) {
|
|
37
|
+
<lucide-icon
|
|
38
|
+
[name]="iconsService.icons.chevronDown"
|
|
39
|
+
size="16"
|
|
40
|
+
class="transition duration-300 ease-in-out text-gray-400"
|
|
41
|
+
[ngClass]="{ 'rotate-180': isColumnSelectorOpen }"
|
|
42
|
+
></lucide-icon>
|
|
43
|
+
} @else {
|
|
44
|
+
<lucide-icon
|
|
45
|
+
[name]="iconsService.icons.loading"
|
|
46
|
+
size="16"
|
|
47
|
+
class="text-gray-400 animate-spin"
|
|
48
|
+
></lucide-icon>
|
|
49
|
+
}
|
|
50
|
+
</div>
|
|
51
|
+
</button>
|
|
52
|
+
</div>
|
|
31
53
|
</div>
|
|
32
54
|
|
|
33
55
|
<!-- Dropdown positioned outside the flow -->
|
|
34
56
|
@if (isColumnSelectorOpen) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
57
|
+
<div
|
|
58
|
+
@modalTransition
|
|
59
|
+
[class]="
|
|
60
|
+
'absolute z-[100] min-w-[250px] mt-1 bg-background dark:bg-dark-background rounded-lg shadow-lg border border-border border-dark-border' +
|
|
61
|
+
' ' +
|
|
62
|
+
classes
|
|
63
|
+
"
|
|
64
|
+
[style.width.px]="dropdownWidth"
|
|
65
|
+
[style.top.px]="dropdownTop"
|
|
66
|
+
[style.left.px]="dropdownLeft"
|
|
67
|
+
[ngClass]="getButtonNgClass()"
|
|
68
|
+
>
|
|
69
|
+
<div class="pt-1 pl-3 pr-3 pb-3">
|
|
70
|
+
<div
|
|
71
|
+
class="text-[10px] font-medium text-gray-500 dark:text-gray-500 mb-1"
|
|
72
|
+
>
|
|
73
|
+
{{ title }}
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<!-- Search -->
|
|
77
|
+
@if (type === "searchable" && isSearch) {
|
|
78
|
+
<div class="mb-2 relative">
|
|
79
|
+
<input
|
|
80
|
+
type="text"
|
|
81
|
+
[(ngModel)]="searchTerm"
|
|
82
|
+
(input)="onSearchInput()"
|
|
83
|
+
placeholder="Buscar..."
|
|
84
|
+
class="input bg-dark-foreground dark:bg-foreground text-black dark:text-white w-full px-3 py-2 text-sm max-[400px]:h-[35px] max-[400px]:text-[12px] border border-border dark:border-dark-border rounded focus:outline-none focus:ring-2 focus:ring-primary"
|
|
85
|
+
/>
|
|
86
|
+
|
|
87
|
+
<div class="absolute flex right-3 top-1/2 transform -translate-y-1/2">
|
|
88
|
+
@if (searchTerm) {
|
|
89
|
+
<button
|
|
90
|
+
type="button"
|
|
91
|
+
(click)="clearSearchTerm()"
|
|
92
|
+
class="pr-1 mr-1 text-gray-400 hover:text-gray-600 focus:outline-none cursor-pointer"
|
|
93
|
+
>
|
|
94
|
+
<lucide-icon
|
|
95
|
+
[name]="iconsService.icons.close"
|
|
96
|
+
size="16"
|
|
97
|
+
></lucide-icon>
|
|
98
|
+
</button>
|
|
99
|
+
}
|
|
100
|
+
<lucide-icon
|
|
101
|
+
[name]="iconsService.icons.search"
|
|
102
|
+
size="16"
|
|
103
|
+
class="text-gray-400"
|
|
104
|
+
></lucide-icon>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
<!-- Dropdown -->
|
|
110
|
+
<div
|
|
111
|
+
class="max-h-45 max-[400px]:max-h-38 overflow-x-hidden overflow-y-auto flex flex-col gap-1 scroll-element"
|
|
112
|
+
>
|
|
113
|
+
@if (isLoading) {
|
|
114
|
+
<div
|
|
115
|
+
class="flex gap-3 text-black/50 dark:text-white/50 items-center justify-center py-4"
|
|
116
|
+
>
|
|
117
|
+
<lucide-icon
|
|
118
|
+
[name]="iconsService.icons.loading"
|
|
119
|
+
size="20"
|
|
120
|
+
class="animate-spin"
|
|
121
|
+
></lucide-icon>
|
|
122
|
+
Cargando...
|
|
123
|
+
</div>
|
|
124
|
+
} @else {
|
|
125
|
+
@for (option of filteredOptions; track option.value) {
|
|
126
|
+
<div
|
|
127
|
+
onKeyDown
|
|
128
|
+
(click)="selectOption(option)"
|
|
129
|
+
class="flex gap-2 items-center border border-accent dark:border-dark-accent/50 px-3 py-2 rounded text-sm max-[400px]:h-[35px] max-[400px]:text-[12px] cursor-pointer text-black! dark:text-white! hover:bg-accent/50 hover:dark:bg-dark-accent/40"
|
|
130
|
+
[ngClass]="{
|
|
131
|
+
'bg-accent! dark:bg-dark-accent/80!':
|
|
132
|
+
selectedValue === option.value,
|
|
133
|
+
'text-black': selectedValue === option.value,
|
|
134
|
+
}"
|
|
135
|
+
>
|
|
136
|
+
@if (selectedValue === option.value) {
|
|
137
|
+
<lucide-icon
|
|
138
|
+
[name]="iconsService.icons.check"
|
|
139
|
+
size="15"
|
|
140
|
+
class="transition text-black dark:text-white"
|
|
52
141
|
/>
|
|
142
|
+
} @else {
|
|
143
|
+
<lucide-icon
|
|
144
|
+
[name]="iconsService.icons.squareDashedMousePointer"
|
|
145
|
+
size="15"
|
|
146
|
+
class="transition text-black dark:text-white opacity-40"
|
|
147
|
+
/>
|
|
148
|
+
}
|
|
53
149
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class="pr-1 mr-1 text-gray-400 hover:text-gray-600 focus:outline-none cursor-pointer"
|
|
60
|
-
>
|
|
61
|
-
<lucide-icon [name]="iconsService.icons.close" size="16"></lucide-icon>
|
|
62
|
-
</button>
|
|
63
|
-
}
|
|
64
|
-
<lucide-icon [name]="iconsService.icons.search" size="16" class="text-gray-400"></lucide-icon>
|
|
65
|
-
</div>
|
|
150
|
+
<div
|
|
151
|
+
class="flex items-center break-words whitespace-normal overflow-hidden"
|
|
152
|
+
>
|
|
153
|
+
{{ option.text }}
|
|
154
|
+
</div>
|
|
66
155
|
</div>
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
@if (isLoading) {
|
|
72
|
-
<div class="flex gap-3 text-black/50 dark:text-white/50 items-center justify-center py-4">
|
|
73
|
-
<lucide-icon [name]="iconsService.icons.loading" size="20" class="animate-spin"></lucide-icon>
|
|
74
|
-
Cargando...
|
|
75
|
-
</div>
|
|
76
|
-
} @else {
|
|
77
|
-
@for (option of filteredOptions; track option.value) {
|
|
78
|
-
<div onKeyDown
|
|
79
|
-
(click)="selectOption(option)"
|
|
80
|
-
class="px-3 py-2 rounded text-sm max-[400px]:h-[35px] max-[400px]:text-[12px] cursor-pointer text-black! dark:text-white! hover:bg-accent/50 hover:dark:bg-dark-accent/40"
|
|
81
|
-
[ngClass]="{'bg-accent! dark:bg-dark-accent/80!': selectedValue === option.value, 'text-black': selectedValue === option.value}">
|
|
82
|
-
<div class="flex items-center break-words whitespace-normal overflow-hidden">
|
|
83
|
-
{{option.text}}
|
|
84
|
-
</div>
|
|
85
|
-
</div>
|
|
86
|
-
}
|
|
87
|
-
@if (filteredOptions.length === 0) {
|
|
88
|
-
<div class="px-3 py-2 text-sm text-gray-500">No hay opciones disponibles</div>
|
|
89
|
-
}
|
|
90
|
-
}
|
|
156
|
+
}
|
|
157
|
+
@if (filteredOptions.length === 0) {
|
|
158
|
+
<div class="px-3 py-2 text-sm text-gray-500">
|
|
159
|
+
No hay opciones disponibles
|
|
91
160
|
</div>
|
|
92
|
-
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
</div>
|
|
93
164
|
</div>
|
|
165
|
+
</div>
|
|
94
166
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
import { Component, Input, Output, EventEmitter, ElementRef, ViewChild, OnDestroy, ChangeDetectorRef, AfterViewInit, OnInit, SimpleChanges, OnChanges, } from "@angular/core"
|
|
2
3
|
import { FormsModule, ControlValueAccessor, ReactiveFormsModule, NG_VALUE_ACCESSOR } from "@angular/forms"
|
|
3
4
|
import { CommonModule } from "@angular/common"
|
|
@@ -55,9 +56,9 @@ export class JDropdownSelectComponent implements ControlValueAccessor, AfterView
|
|
|
55
56
|
|
|
56
57
|
@Input() isSearch = true;
|
|
57
58
|
@Input() isFilterSelect = false;
|
|
58
|
-
|
|
59
|
+
|
|
59
60
|
@Input() classes: string = '';
|
|
60
|
-
@Input()
|
|
61
|
+
@Input() ngClasses: { [key: string]: boolean } = {};
|
|
61
62
|
|
|
62
63
|
@Output() selectionChange = new EventEmitter<any>();
|
|
63
64
|
@Output() fullData = new EventEmitter<any[]>();
|
|
@@ -662,4 +663,15 @@ export class JDropdownSelectComponent implements ControlValueAccessor, AfterView
|
|
|
662
663
|
const isInitialState = this.selectedValue === null
|
|
663
664
|
return isSearchActive || isInitialState
|
|
664
665
|
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Get the ngClass for the button based on disabled and loading state
|
|
669
|
+
* @returns
|
|
670
|
+
*/
|
|
671
|
+
getButtonNgClass(): { [key: string]: boolean } {
|
|
672
|
+
return {
|
|
673
|
+
'opacity-50 cursor-not-allowed pointer-events-none': this.isDisabled || this.isLoading,
|
|
674
|
+
...this.ngClasses,
|
|
675
|
+
};
|
|
676
|
+
}
|
|
665
677
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
classes="secondary"
|
|
6
6
|
[icon]="btnIcon"
|
|
7
7
|
[disabled]="isDisabled"
|
|
8
|
+
[ngClasses]="getButtonNgClass()"
|
|
8
9
|
>
|
|
9
10
|
{{btnText}}
|
|
10
11
|
</JButton>
|
|
@@ -18,6 +19,7 @@
|
|
|
18
19
|
[style.width.px]="dropdownWidth"
|
|
19
20
|
[style.top.px]="dropdownTop"
|
|
20
21
|
[style.left.px]="dropdownLeft"
|
|
22
|
+
[ngClass]="getButtonNgClass()"
|
|
21
23
|
>
|
|
22
24
|
<div class="pt-1 pl-3 pr-3 pb-3">
|
|
23
25
|
<div class="text-[10px] font-medium text-gray-500 dark:text-gray-500 mb-1">{{title}}</div>
|
|
@@ -31,6 +31,7 @@ export class JMultiTableSelectComponent implements AfterViewInit, OnInit, OnChan
|
|
|
31
31
|
@Input() showActions = true;
|
|
32
32
|
@Input() isFilterSelect = false;
|
|
33
33
|
|
|
34
|
+
@Input() ngClasses: { [key: string]: boolean } = {};
|
|
34
35
|
|
|
35
36
|
@Output() columnToggle = new EventEmitter<{ column: TableColumn<any>; visible: boolean }>();
|
|
36
37
|
@Input() columns: TableColumn<any>[] = [];
|
|
@@ -413,4 +414,15 @@ export class JMultiTableSelectComponent implements AfterViewInit, OnInit, OnChan
|
|
|
413
414
|
const column = this.columns.find((col) => col.key === key);
|
|
414
415
|
return column?.visible ?? false;
|
|
415
416
|
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Get the ngClass for the button based on disabled and loading state
|
|
420
|
+
* @returns
|
|
421
|
+
*/
|
|
422
|
+
getButtonNgClass(): { [key: string]: boolean } {
|
|
423
|
+
return {
|
|
424
|
+
'opacity-50 cursor-not-allowed pointer-events-none': this.isDisabled,
|
|
425
|
+
...this.ngClasses,
|
|
426
|
+
};
|
|
427
|
+
}
|
|
416
428
|
}
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
</div>
|
|
42
42
|
</div>
|
|
43
43
|
|
|
44
|
-
<div class="
|
|
44
|
+
<div class="relative border border-border dark:border-dark-border rounded">
|
|
45
45
|
<div class="overflow-x-auto rounded scroll-element pr-0!" style="overflow-y: hidden;">
|
|
46
46
|
<table class="min-w-full bg-white dark:bg-dark-background rounded">
|
|
47
47
|
<thead class="bg-primary dark:bg-dark-primary text-white dark:text-white select-none h-[50px]">
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
[isSearch]="isSearch"
|
|
11
11
|
[isShowColumns]="isEyeColumn"
|
|
12
12
|
(search)="onSearch()"
|
|
13
|
+
[isbackground]="isbackground"
|
|
13
14
|
[searchPlaceholder]="searchPlaceholder"
|
|
14
15
|
[isItemsPerPage]="isItemsPerPage"
|
|
15
16
|
[(itemsPerPage)]="itemsPerPage"
|
|
@@ -41,13 +42,14 @@
|
|
|
41
42
|
[pages]="pages"
|
|
42
43
|
(pageChange)="handlePageChange($event)"
|
|
43
44
|
[isLoading]="isLoading('pagination')"
|
|
45
|
+
[isbackground]="isbackground"
|
|
44
46
|
/>
|
|
45
47
|
</div>
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
<!-- Table -->
|
|
49
51
|
<div
|
|
50
|
-
class="relative block max-[
|
|
52
|
+
class="relative block max-[768px]:hidden border border-border dark:border-dark-border rounded"
|
|
51
53
|
>
|
|
52
54
|
<div
|
|
53
55
|
class="overflow-x-auto rounded scroll-element pr-0!"
|
|
@@ -491,7 +493,7 @@
|
|
|
491
493
|
>
|
|
492
494
|
<div class="flex justify-center items-center">
|
|
493
495
|
@if (optionsType === "dropdown") {
|
|
494
|
-
<
|
|
496
|
+
<JOptionsCoachMenu
|
|
495
497
|
[optionsTable]="optionsTable"
|
|
496
498
|
[group]="item"
|
|
497
499
|
[rowId]="'group_' + item.id || 'group_' + $index"
|
|
@@ -798,7 +800,7 @@
|
|
|
798
800
|
class="relative overflow-visible flex justify-center items-center space-x-2 min-w-[50px] px-4 py-2 h-[50px]"
|
|
799
801
|
>
|
|
800
802
|
@if (optionsType === "dropdown") {
|
|
801
|
-
<
|
|
803
|
+
<JOptionsCoachMenu
|
|
802
804
|
[optionsTable]="optionsTable"
|
|
803
805
|
[group]="group"
|
|
804
806
|
[rowId]="
|
|
@@ -954,7 +956,7 @@
|
|
|
954
956
|
</div>
|
|
955
957
|
|
|
956
958
|
<!-- TABLE MOVILE -->
|
|
957
|
-
<div class="hidden max-[
|
|
959
|
+
<div class="hidden max-[768px]:block">
|
|
958
960
|
<div class="flex flex-col gap-3">
|
|
959
961
|
@if (isLoading("initialLoad") && displayData.length === 0) {
|
|
960
962
|
<div
|
|
@@ -990,14 +992,14 @@
|
|
|
990
992
|
|
|
991
993
|
<div class="flex-1 min-w-0 max-w-full overflow-hidden">
|
|
992
994
|
<div
|
|
993
|
-
class="font-bold text-[12px] leading-tight block overflow-hidden text-ellipsis whitespace-nowrap max-w-[200px]"
|
|
995
|
+
class="font-bold text-[12px] leading-tight block overflow-hidden text-ellipsis whitespace-nowrap max-[400px]:max-w-[200px] max-[768px]:max-w-[500px]"
|
|
994
996
|
>
|
|
995
997
|
{{ getMobileMainTitle(item) }}
|
|
996
998
|
</div>
|
|
997
999
|
|
|
998
1000
|
@if (getMobileMainDescription(item)) {
|
|
999
1001
|
<div
|
|
1000
|
-
class="text-[12px] leading-snug break-words whitespace-normal max-w-[200px]"
|
|
1002
|
+
class="text-[12px] leading-snug break-words whitespace-normal max-[400px]:max-w-[200px] max-[768px]:max-w-[500px]"
|
|
1001
1003
|
>
|
|
1002
1004
|
{{ getMobileMainDescription(item) }}
|
|
1003
1005
|
</div>
|
|
@@ -1367,6 +1369,7 @@
|
|
|
1367
1369
|
[pages]="pages"
|
|
1368
1370
|
(pageChange)="handlePageChange($event)"
|
|
1369
1371
|
[isLoading]="isLoading('pagination')"
|
|
1372
|
+
[isbackground]="isbackground"
|
|
1370
1373
|
/>
|
|
1371
1374
|
</div>
|
|
1372
1375
|
}
|
|
@@ -13,16 +13,16 @@ import { JCompletePaginatorComponent } from '../../paginator/paginator-complete/
|
|
|
13
13
|
import { JCompleteFilterComponent } from '../../filter/filter-complete/complete-filter.component';
|
|
14
14
|
import { JButtonComponent } from '../../button/button.component';
|
|
15
15
|
import { JInputCheckboxComponent } from '../../checkbox/checkbox-input/input-checkbox.component';
|
|
16
|
-
import { JOptionsTableMenuComponent } from '../../menu/menu-options-table/options-table-menu.component';
|
|
17
16
|
import { JDialogComponent } from '../../dialog/dialog.component';
|
|
18
17
|
import { JDropdownSelectComponent } from '../../select/select-dropdown/dropdown-select.component';
|
|
19
18
|
import { JInputComponent } from '../../input/input/input.component';
|
|
20
19
|
import { JImageViewerComponent } from '../../viewer/viewer-image/image-viewer.component';
|
|
20
|
+
import { JOptionsCoachMenuComponent } from '../../menu/options-coach-menu/options-coach-menu.component';
|
|
21
21
|
|
|
22
22
|
@Component({
|
|
23
23
|
selector: 'JCompleteCrudTable',
|
|
24
24
|
standalone: true,
|
|
25
|
-
imports: [CommonModule, FormsModule, JCompletePaginatorComponent, JCompleteFilterComponent, LucideAngularModule, JButtonComponent, JInputCheckboxComponent,
|
|
25
|
+
imports: [CommonModule, FormsModule, JCompletePaginatorComponent, JCompleteFilterComponent, LucideAngularModule, JButtonComponent, JInputCheckboxComponent, JDialogComponent, JImageViewerComponent, JDropdownSelectComponent, JInputComponent, JOptionsCoachMenuComponent],
|
|
26
26
|
templateUrl: './complete-crud-table.component.html',
|
|
27
27
|
styleUrl: './complete-crud-table.component.scss',
|
|
28
28
|
animations: [
|
|
@@ -66,6 +66,7 @@ export class JCompleteCrudTableComponent implements OnInit {
|
|
|
66
66
|
@Input() defaultFilters: { [key: string]: any } = {};
|
|
67
67
|
@Input() isPaginator = true;
|
|
68
68
|
@Input() isFilter = true;
|
|
69
|
+
@Input() isbackground = false;
|
|
69
70
|
@Input() isSearch = true;
|
|
70
71
|
@Input() isEyeColumn = true;
|
|
71
72
|
@Input() hideRowCondition?: (row: any) => boolean
|