tailjng 0.0.13 → 0.0.15

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 (87) hide show
  1. package/cli/component-manager.js +45 -0
  2. package/cli/dependency-manager.js +52 -0
  3. package/cli/file-operations.js +88 -0
  4. package/cli/index.js +51 -0
  5. package/cli/settings/colors.js +17 -0
  6. package/cli/settings/components-list.js +87 -0
  7. package/cli/settings/header-generator.js +42 -0
  8. package/cli/settings/path-utils.js +50 -0
  9. package/cli/settings/prompt-utils.js +37 -0
  10. package/cli/settings/tailwind-check.js +21 -0
  11. package/fesm2022/tailjng.mjs +903 -25
  12. package/fesm2022/tailjng.mjs.map +1 -1
  13. package/lib/config/tailjng-config.token.d.ts +3 -0
  14. package/lib/interfaces/alert/dialog-alert.interface.d.ts +52 -0
  15. package/lib/interfaces/alert/toast-alert.interface.d.ts +52 -0
  16. package/lib/interfaces/config.interface.d.ts +5 -0
  17. package/lib/interfaces/crud/api-response.d.ts +29 -0
  18. package/lib/interfaces/crud/crud.interface.d.ts +103 -0
  19. package/lib/services/alert/dialog-alert.service.d.ts +24 -0
  20. package/lib/services/alert/toast-alert.service.d.ts +26 -0
  21. package/lib/services/crud/converter-crud.service.d.ts +41 -0
  22. package/lib/services/crud/generic-crud.service.d.ts +81 -0
  23. package/lib/services/http/error-handler-http.service.d.ts +26 -0
  24. package/lib/services/http/params-http.service.d.ts +13 -0
  25. package/lib/services/static/icons.service.d.ts +31 -0
  26. package/lib/services/transformer/calendar.service.d.ts +71 -0
  27. package/package.json +5 -3
  28. package/public-api.d.ts +10 -3
  29. package/src/lib/components/alert/dialog-alert/dialog-alert.component.css +0 -0
  30. package/src/lib/components/alert/dialog-alert/dialog-alert.component.html +72 -0
  31. package/src/lib/components/alert/dialog-alert/dialog-alert.component.ts +66 -0
  32. package/src/lib/components/alert/toast-alert/toast-alert.component.css +5 -0
  33. package/src/lib/components/alert/toast-alert/toast-alert.component.html +76 -0
  34. package/src/lib/components/alert/toast-alert/toast-alert.component.ts +87 -0
  35. package/src/lib/components/button/button.component.css +0 -0
  36. package/src/lib/components/button/button.component.html +36 -0
  37. package/src/lib/components/button/button.component.ts +95 -0
  38. package/src/lib/components/checkbox/input-checkbox/input-checkbox.component.css +0 -0
  39. package/src/lib/components/checkbox/input-checkbox/input-checkbox.component.html +23 -0
  40. package/src/lib/components/checkbox/input-checkbox/input-checkbox.component.ts +44 -0
  41. package/src/lib/components/checkbox/switch-checkbox/switch-checkbox.component.css +0 -0
  42. package/src/lib/components/checkbox/switch-checkbox/switch-checkbox.component.html +26 -0
  43. package/src/lib/components/checkbox/switch-checkbox/switch-checkbox.component.ts +29 -0
  44. package/src/lib/components/color/colors.service.ts +109 -0
  45. package/src/lib/components/dialog/dialog.component.css +8 -0
  46. package/src/lib/components/dialog/dialog.component.html +57 -0
  47. package/src/lib/components/dialog/dialog.component.ts +179 -0
  48. package/src/lib/components/image/viewer-image/viewer-image.component.css +4 -0
  49. package/src/lib/components/image/viewer-image/viewer-image.component.html +75 -0
  50. package/src/lib/components/image/viewer-image/viewer-image.component.ts +131 -0
  51. package/src/lib/components/input/file-input/file-input.component.css +0 -0
  52. package/src/lib/components/input/file-input/file-input.component.html +49 -0
  53. package/src/lib/components/input/file-input/file-input.component.ts +218 -0
  54. package/src/lib/components/input/input/input.component.css +0 -0
  55. package/src/lib/components/input/input/input.component.html +24 -0
  56. package/src/lib/components/input/input/input.component.ts +78 -0
  57. package/src/lib/components/input/range-input/range-input.component.css +0 -0
  58. package/src/lib/components/input/range-input/range-input.component.html +64 -0
  59. package/src/lib/components/input/range-input/range-input.component.ts +78 -0
  60. package/src/lib/components/input/textarea-input/textarea-input.component.css +0 -0
  61. package/src/lib/components/input/textarea-input/textarea-input.component.html +21 -0
  62. package/src/lib/components/input/textarea-input/textarea-input.component.ts +75 -0
  63. package/src/lib/components/label/label.component.html +1 -1
  64. package/src/lib/components/label/label.component.ts +1 -1
  65. package/src/lib/components/mode-toggle/mode-toggle.component.css +0 -0
  66. package/src/lib/components/mode-toggle/mode-toggle.component.html +8 -0
  67. package/src/lib/components/mode-toggle/mode-toggle.component.ts +61 -0
  68. package/src/lib/components/progress-bar/progress-bar.component.css +0 -0
  69. package/src/lib/components/progress-bar/progress-bar.component.html +22 -0
  70. package/src/lib/components/progress-bar/progress-bar.component.ts +20 -0
  71. package/src/lib/components/select/dropdown/dropdown.component.css +0 -0
  72. package/src/lib/components/select/dropdown/dropdown.component.html +95 -0
  73. package/src/lib/components/select/dropdown/dropdown.component.ts +562 -0
  74. package/src/lib/components/select/multi-dropdown/multi-dropdown.component.css +0 -0
  75. package/src/lib/components/select/multi-dropdown/multi-dropdown.component.html +87 -0
  76. package/src/lib/components/select/multi-dropdown/multi-dropdown.component.ts +315 -0
  77. package/src/lib/components/select/multi-table/multi-table.component.css +0 -0
  78. package/src/lib/components/select/multi-table/multi-table.component.html +83 -0
  79. package/src/lib/components/select/multi-table/multi-table.component.ts +230 -0
  80. package/src/lib/components/toggle-radio/toggle-radio.component.css +0 -0
  81. package/src/lib/components/toggle-radio/toggle-radio.component.html +51 -0
  82. package/src/lib/components/toggle-radio/toggle-radio.component.ts +203 -0
  83. package/src/styles.css +126 -0
  84. package/cli/tailjng.js +0 -105
  85. package/lib/services/icons.service.d.ts +0 -9
  86. package/lib/tailjng.component.d.ts +0 -5
  87. package/lib/tailjng.service.d.ts +0 -6
@@ -0,0 +1,218 @@
1
+ import { Component, Input, forwardRef, ViewChild, ElementRef, OnChanges, SimpleChanges } from '@angular/core';
2
+ import { ControlValueAccessor, NG_VALUE_ACCESSOR, FormsModule, ReactiveFormsModule } from '@angular/forms';
3
+ import { NgClass, CommonModule } from '@angular/common';
4
+ import { LucideAngularModule } from 'lucide-angular';
5
+ import { JIconsService } from 'tailjng';
6
+
7
+ @Component({
8
+ selector: 'JFileInput',
9
+ imports: [FormsModule, ReactiveFormsModule, NgClass, LucideAngularModule, CommonModule],
10
+ templateUrl: './file-input.component.html',
11
+ styleUrl: './file-input.component.css',
12
+ providers: [
13
+ {
14
+ provide: NG_VALUE_ACCESSOR,
15
+ useExisting: forwardRef(() => JFileInputComponent),
16
+ multi: true
17
+ }
18
+ ]
19
+ })
20
+ export class JFileInputComponent implements ControlValueAccessor, OnChanges {
21
+
22
+ @Input() id?: string;
23
+ @Input() name?: string;
24
+
25
+ @Input() accept: string = '';
26
+ @Input() multiple: boolean = false;
27
+
28
+ @Input() disabled: boolean = false;
29
+ @Input() required: boolean = false;
30
+ @Input() clearButton: boolean = false;
31
+
32
+
33
+ @Input() showImage: boolean = false;
34
+ @Input() widthImgFile: number = 0;
35
+ @Input() heightImgFile: number = 0;
36
+
37
+ @ViewChild('fileInput') fileInputRef!: ElementRef<HTMLInputElement>;
38
+
39
+ innerValue: any = '';
40
+ previewUrl: string | null = null;
41
+
42
+ // This variable is used to track if the file input has been cleared
43
+ public fileInputCleared = false
44
+
45
+ get value(): any {
46
+ return this.innerValue;
47
+ }
48
+
49
+ // ControlValueAccessor
50
+ onChange: any = () => { };
51
+ onTouched: any = () => { };
52
+
53
+ constructor(public readonly iconsService: JIconsService) { }
54
+
55
+ /**
56
+ * Writes a value to the component.
57
+ * @param val
58
+ */
59
+ writeValue(val: any): void {
60
+ this.innerValue = val;
61
+
62
+ // If the value is null or empty, clear the preview
63
+ if (!val) {
64
+ this.previewUrl = null;
65
+
66
+ // If the value is set to null from outside (e.g., from the form)
67
+ // we need to reset the file input
68
+ if (this.fileInputRef?.nativeElement) {
69
+ this.fileInputRef.nativeElement.value = ""
70
+ this.fileInputCleared = true
71
+ }
72
+ }
73
+ }
74
+
75
+
76
+
77
+ /**
78
+ * Registers a callback function that is called when the value changes.
79
+ * @param fn The callback function.
80
+ */
81
+ registerOnChange(fn: any): void {
82
+ this.onChange = fn;
83
+ }
84
+
85
+
86
+
87
+ /**
88
+ * Registers a callback function that is called when the input is touched.
89
+ * @param fn The callback function.
90
+ */
91
+ registerOnTouched(fn: any): void {
92
+ this.onTouched = fn;
93
+ }
94
+
95
+
96
+
97
+ /**
98
+ * Sets the disabled state of the component.
99
+ * If disabled, it clears the inner value and preview URL.
100
+ * @param isDisabled
101
+ */
102
+ setDisabledState(isDisabled: boolean): void {
103
+ if (isDisabled) {
104
+ this.innerValue = null;
105
+ this.previewUrl = null;
106
+ }
107
+ }
108
+
109
+
110
+
111
+ /**
112
+ * Handles changes to the component's inputs.
113
+ * If the value changes to null or empty, it clears the preview URL.
114
+ * @param changes
115
+ */
116
+ ngOnChanges(changes: SimpleChanges): void {
117
+ // If the value is null or empty, clear the preview
118
+ if (changes['value'] && !this.value) {
119
+ this.previewUrl = null;
120
+ }
121
+ }
122
+
123
+
124
+
125
+ /**
126
+ * Handles the file selection event.
127
+ * It reads the selected file(s) and updates the inner value and preview URL if applicable
128
+ * @param event
129
+ */
130
+ onFileSelected(event: Event): void {
131
+ const input = event.target as HTMLInputElement
132
+ const files = input.files
133
+
134
+ if (files && files.length > 0) {
135
+ const value = this.multiple ? Array.from(files) : files[0]
136
+ this.innerValue = value
137
+ this.onChange(value)
138
+ this.onTouched()
139
+ this.fileInputCleared = false
140
+
141
+ if (!this.multiple && value instanceof File && value.type?.startsWith("image")) {
142
+ const reader = new FileReader()
143
+ reader.onload = () => {
144
+ this.previewUrl = reader.result as string
145
+ }
146
+ reader.readAsDataURL(value)
147
+ } else {
148
+ this.previewUrl = null
149
+ }
150
+ }
151
+ }
152
+
153
+
154
+
155
+ /**
156
+ * Clears the file input and resets the preview URL.
157
+ * This method also resets the file input field so that it can be re-triggered.
158
+ */
159
+ clearFile(): void {
160
+ this.innerValue = null
161
+ this.previewUrl = null
162
+ this.onChange(this.multiple ? [] : null)
163
+ this.onTouched()
164
+
165
+ // Reset the file input field so that it can be re-triggered
166
+ if (this.fileInputRef?.nativeElement) {
167
+ this.fileInputRef.nativeElement.value = ""
168
+ this.fileInputCleared = true
169
+ }
170
+ }
171
+
172
+
173
+
174
+ /**
175
+ * Resets the file input to its initial state.
176
+ */
177
+ resetFileInput(): void {
178
+ this.clearFile()
179
+
180
+ // Create a new input element to replace the current one
181
+ // This forces the browser to recognize any selected file as "new"
182
+ if (this.fileInputRef?.nativeElement) {
183
+ const parent = this.fileInputRef.nativeElement.parentNode
184
+ if (parent) {
185
+
186
+ // We need to create a new input element
187
+ const oldInput = this.fileInputRef.nativeElement
188
+ const newInput = document.createElement("input")
189
+
190
+ // Copy all important attributes
191
+ newInput.type = "file"
192
+ if (this.accept) newInput.accept = this.accept
193
+ if (this.multiple) newInput.multiple = this.multiple
194
+ if (this.name) newInput.name = this.name
195
+ if (this.id) newInput.id = this.id
196
+ if (this.disabled) newInput.disabled = this.disabled
197
+ if (this.required) newInput.required = this.required
198
+
199
+ // Copy all event listeners
200
+ newInput.addEventListener("change", (e) => this.onFileSelected(e))
201
+
202
+ // Replace the input
203
+ parent.replaceChild(newInput, oldInput)
204
+
205
+ // Update the reference
206
+ setTimeout(() => {
207
+ if (this.fileInputRef) {
208
+ this.fileInputRef.nativeElement = newInput as HTMLInputElement
209
+ }
210
+ })
211
+ }
212
+ }
213
+
214
+
215
+ }
216
+
217
+
218
+ }
@@ -0,0 +1,24 @@
1
+ <div class="relative w-full">
2
+ <input
3
+ [type]="type"
4
+ [id]="id"
5
+ [name]="name ?? ''"
6
+ [placeholder]="placeholder"
7
+ [value]="value"
8
+ (input)="onInput($event)"
9
+ [required]="required"
10
+ [disabled]="disabled"
11
+ (blur)="onTouched()"
12
+ [ngClass]="combinedNgClass"
13
+ [class]="classes"
14
+ class="input w-full h-[40px] bg-background dark:bg-dark-background border border-border dark:border-dark-border text-black dark:text-white rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary transition duration-200"
15
+ />
16
+
17
+ @if (value && clearButton) {
18
+ <button type="button"
19
+ 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"
20
+ (click)="clearInput()">
21
+ <lucide-icon [name]="iconsService.icons.close" class="w-4 h-4" />
22
+ </button>
23
+ }
24
+ </div>
@@ -0,0 +1,78 @@
1
+ import { Component, Input } from '@angular/core';
2
+ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
3
+ import { NgClass, CommonModule } from '@angular/common';
4
+ import { LucideAngularModule } from 'lucide-angular';
5
+ import { JIconsService } from 'tailjng';
6
+
7
+ @Component({
8
+ selector: 'JInput',
9
+ imports: [FormsModule, ReactiveFormsModule, NgClass, LucideAngularModule, CommonModule],
10
+ templateUrl: './input.component.html',
11
+ styleUrl: './input.component.css'
12
+ })
13
+ export class JInputComponent {
14
+
15
+ @Input() type: 'text' | 'password' | 'number' | 'date' | 'datetime-local' | 'email' = 'text';
16
+ @Input() id?: string;
17
+ @Input() name?: string;
18
+ @Input() placeholder: string = '';
19
+
20
+ @Input() disabled: boolean = false;
21
+ @Input() required: boolean = false;
22
+ @Input() classes: string = '';
23
+ @Input() ngClass: { [key: string]: boolean } = {};
24
+
25
+ @Input() clearButton: boolean = false;
26
+
27
+ innerValue: any = '';
28
+
29
+ get value(): any {
30
+ return this.innerValue;
31
+ }
32
+
33
+ set value(val: any) {
34
+ if (val !== this.innerValue) {
35
+ this.innerValue = val;
36
+ this.onChange(val);
37
+ }
38
+ }
39
+
40
+ get combinedNgClass() {
41
+ return {
42
+ ...(this.ngClass || {}),
43
+ 'opacity-50': this.disabled
44
+ };
45
+ }
46
+
47
+ // ControlValueAccessor
48
+ onChange: any = () => { };
49
+ onTouched: any = () => { };
50
+
51
+ constructor(public readonly iconsService: JIconsService) { }
52
+
53
+
54
+ /**
55
+ * Writes a value to the component.
56
+ * @param event
57
+ */
58
+ onInput(event: Event): void {
59
+ const target = event.target as HTMLInputElement | HTMLTextAreaElement;
60
+ this.value = target.value;
61
+ this.onChange(this.value);
62
+ this.onTouched();
63
+ }
64
+
65
+
66
+
67
+ /**
68
+ * Clears the input value and resets the component state.
69
+ * This method is typically used when a clear button is clicked.
70
+ */
71
+ clearInput(): void {
72
+ this.value = '';
73
+ this.onChange('');
74
+ this.onTouched();
75
+ }
76
+
77
+
78
+ }
@@ -0,0 +1,64 @@
1
+ <div class="w-full">
2
+ @if (placeholder) {
3
+ @if (isLabel) {
4
+
5
+ <label [for]="id" class="flex text-[15px] font-bold text-black dark:text-white justify-between mb-1 opacity-80">
6
+ <span>{{ placeholder }}</span>
7
+ <span>{{ value | number:'1.0-2' }}{{simbol}}</span>
8
+ </label>
9
+
10
+ } @else {
11
+ <label [for]="id" class="block text-[15px] font-bold text-black dark:text-white text-center mb-1 opacity-80">{{ placeholder }}</label>
12
+ }
13
+ }
14
+
15
+ <div class="relative flex gap-2 w-full items-center justify-center align-center items-center justify-center align-center">
16
+ @if (min !== null) {
17
+ <span class="text-[15px] font-bold text-gray-500 mt-1 text-center">{{min}}{{simbol}}</span>
18
+ }
19
+ <input
20
+ type="range"
21
+ [id]="id"
22
+ [name]="name ?? ''"
23
+ [min]="min"
24
+ [max]="max"
25
+ [step]="step"
26
+ [required]="required"
27
+ [disabled]="disabled"
28
+ [(ngModel)]="value"
29
+ (blur)="onTouched()"
30
+ [ngClass]="combinedNgClass"
31
+ [class]="classes"
32
+ class="
33
+ w-full h-5 bg-background dark:bg-dark-background border border-border dark:border-dark-border
34
+ rounded-lg appearance-none cursor-pointer focus:outline-none focus:ring-2 focus:ring-primary transition duration-200
35
+
36
+ [&::-webkit-slider-thumb]:appearance-none
37
+ [&::-webkit-slider-thumb]:h-8
38
+ [&::-webkit-slider-thumb]:w-8
39
+ [&::-webkit-slider-thumb]:rounded-full
40
+ [&::-webkit-slider-thumb]:cursor-pointer
41
+ [&::-webkit-slider-thumb]:bg-dark-primary
42
+ dark:[&::-webkit-slider-thumb]:bg-primary
43
+ [&::-webkit-slider-thumb:hover]:bg-primary
44
+ dark:[&::-webkit-slider-thumb:hover]:bg-dark-primary
45
+
46
+ [&::-moz-range-thumb]:h-4
47
+ [&::-moz-range-thumb]:w-4
48
+ [&::-moz-range-thumb]:rounded-full
49
+ [&::-moz-range-thumb]:bg-primary
50
+ [&::-moz-range-thumb]:cursor-pointer
51
+ [&::-moz-range-thumb:hover]:bg-primary
52
+ dark:[&::-moz-range-thumb:hover]:bg-dark-primary
53
+ "
54
+ />
55
+
56
+ @if (max) {
57
+ <span class="text-[15px] font-bold text-gray-500 mt-1 text-center">{{max}}{{simbol}}</span>
58
+ }
59
+ </div>
60
+
61
+ @if (!isLabel) {
62
+ <div class="text-xl font-bold text-gray-500 mt-1 text-center">{{ value }}</div>
63
+ }
64
+ </div>
@@ -0,0 +1,78 @@
1
+ import { Component, Input } from '@angular/core';
2
+ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
3
+ import { NgClass, CommonModule } from '@angular/common';
4
+ import { LucideAngularModule } from 'lucide-angular';
5
+
6
+ @Component({
7
+ selector: 'JRangeInput',
8
+ imports: [FormsModule, ReactiveFormsModule, NgClass, LucideAngularModule, CommonModule],
9
+ templateUrl: './range-input.component.html',
10
+ styleUrl: './range-input.component.css'
11
+ })
12
+ export class JRangeInputComponent {
13
+
14
+ @Input() id?: string;
15
+ @Input() name?: string;
16
+ @Input() placeholder: string = '';
17
+
18
+ @Input() disabled: boolean = false;
19
+ @Input() required: boolean = false;
20
+ @Input() classes: string = '';
21
+ @Input() ngClass: { [key: string]: boolean } = {};
22
+
23
+ @Input() min: number = 0;
24
+ @Input() max: number = 100;
25
+ @Input() step: number = 1;
26
+
27
+ @Input() isLabel: boolean = false;
28
+ @Input() simbol: string = '';
29
+
30
+ innerValue: any = '';
31
+
32
+ get value(): any {
33
+ return this.innerValue;
34
+ }
35
+
36
+ set value(val: any) {
37
+ if (val !== this.innerValue) {
38
+ this.innerValue = val;
39
+ this.onChange(val);
40
+ }
41
+ }
42
+
43
+ get combinedNgClass() {
44
+ return {
45
+ ...(this.ngClass || {}),
46
+ 'opacity-50': this.disabled
47
+ };
48
+ }
49
+
50
+ // ControlValueAccessor
51
+ onChange: any = () => { };
52
+ onTouched: any = () => { };
53
+
54
+ /**
55
+ * Writes a value to the component.
56
+ * @param event
57
+ */
58
+ onInput(event: Event): void {
59
+ const target = event.target as HTMLInputElement | HTMLTextAreaElement;
60
+ this.value = target.value;
61
+ this.onChange(this.value);
62
+ this.onTouched();
63
+ }
64
+
65
+
66
+
67
+ /**
68
+ * Clears the input value and resets the component state.
69
+ * This method is typically used when a clear button is clicked.
70
+ */
71
+ clearInput(): void {
72
+ this.value = '';
73
+ this.onChange('');
74
+ this.onTouched();
75
+ }
76
+
77
+
78
+ }
@@ -0,0 +1,21 @@
1
+ <div class="relative w-full">
2
+ <textarea
3
+ [id]="id"
4
+ [name]="name ?? ''"
5
+ [placeholder]="placeholder"
6
+ [value]="value"
7
+ (input)="onInput($event)"
8
+ [required]="required"
9
+ [disabled]="disabled"
10
+ (blur)="onTouched()"
11
+ [ngClass]="combinedNgClass"
12
+ [class]="classes"
13
+ class="input w-full h-[70px] min-h-[70px] pr-10 bg-background dark:bg-dark-background border border-border dark:border-dark-border text-black dark:text-white rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary transition duration-200"
14
+ ></textarea>
15
+
16
+ @if (value && clearButton) {
17
+ <button type="button" 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" (click)="clearInput()">
18
+ <lucide-icon [name]="iconsService.icons.close" class="w-4 h-4" />
19
+ </button>
20
+ }
21
+ </div>
@@ -0,0 +1,75 @@
1
+ import { Component, Input } from '@angular/core';
2
+ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
3
+ import { NgClass, CommonModule } from '@angular/common';
4
+ import { LucideAngularModule } from 'lucide-angular';
5
+ import { JIconsService } from 'tailjng';
6
+
7
+ @Component({
8
+ selector: 'JTextareaInput',
9
+ imports: [FormsModule, ReactiveFormsModule, NgClass, LucideAngularModule, CommonModule],
10
+ templateUrl: './textarea-input.component.html',
11
+ styleUrl: './textarea-input.component.css'
12
+ })
13
+ export class JTextareaInputComponent {
14
+
15
+ @Input() id?: string;
16
+ @Input() name?: string;
17
+ @Input() placeholder: string = '';
18
+
19
+ @Input() disabled: boolean = false;
20
+ @Input() required: boolean = false;
21
+ @Input() classes: string = '';
22
+ @Input() ngClass: { [key: string]: boolean } = {};
23
+ @Input() clearButton: boolean = false;
24
+
25
+ innerValue: any = '';
26
+
27
+ get value(): any {
28
+ return this.innerValue;
29
+ }
30
+
31
+ set value(val: any) {
32
+ if (val !== this.innerValue) {
33
+ this.innerValue = val;
34
+ this.onChange(val);
35
+ }
36
+ }
37
+
38
+ get combinedNgClass() {
39
+ return {
40
+ ...(this.ngClass || {}),
41
+ 'opacity-50': this.disabled
42
+ };
43
+ }
44
+
45
+ // ControlValueAccessor
46
+ onChange: any = () => { };
47
+ onTouched: any = () => { };
48
+
49
+ constructor(public readonly iconsService: JIconsService) { }
50
+
51
+ /**
52
+ * Writes a value to the component.
53
+ * @param event
54
+ */
55
+ onInput(event: Event): void {
56
+ const target = event.target as HTMLInputElement | HTMLTextAreaElement;
57
+ this.value = target.value;
58
+ this.onChange(this.value);
59
+ this.onTouched();
60
+ }
61
+
62
+
63
+
64
+ /**
65
+ * Clears the input value and resets the component state.
66
+ * This method is typically used when a clear button is clicked.
67
+ */
68
+ clearInput(): void {
69
+ this.value = '';
70
+ this.onChange('');
71
+ this.onTouched();
72
+ }
73
+
74
+
75
+ }
@@ -18,7 +18,7 @@
18
18
 
19
19
  @if (tooltip) {
20
20
  <span [jTooltip]="tooltip" [jTooltipPosition]="tooltipPosition" >
21
- <lucide-icon [name]="iconsService.icons.Info" [size]="15" />
21
+ <lucide-icon [name]="iconsService.icons.info" [size]="15" />
22
22
  </span>
23
23
  }
24
24
 
@@ -1,7 +1,7 @@
1
1
  import { NgClass } from '@angular/common';
2
2
  import { Component, Input } from '@angular/core';
3
3
  import { JTooltipDirective } from '../tooltip/tooltip.directive';
4
- import { JIconsService } from '../../services/icons.service';
4
+ import { JIconsService } from 'tailjng';
5
5
  import { LucideAngularModule } from 'lucide-angular';
6
6
 
7
7
  @Component({
@@ -0,0 +1,8 @@
1
+ <button (click)="toggleDarkMode()"
2
+ class="p-2 bg-gray-300 dark:bg-gray-700 text-black dark:text-white rounded-full cursor-pointer">
3
+ @if (theme === 'dark') {
4
+ <lucide-icon [name]="iconsService.icons.moon"></lucide-icon>
5
+ } @else {
6
+ <lucide-icon [name]="iconsService.icons.sun"></lucide-icon>
7
+ }
8
+ </button>
@@ -0,0 +1,61 @@
1
+ import { Component, Inject, PLATFORM_ID } from '@angular/core';
2
+ import { isPlatformBrowser } from '@angular/common';
3
+ import { LucideAngularModule } from 'lucide-angular';
4
+ import { JIconsService } from 'tailjng';
5
+
6
+ @Component({
7
+ selector: 'JModeToggle',
8
+ imports: [LucideAngularModule],
9
+ templateUrl: './mode-toggle.component.html',
10
+ styleUrl: './mode-toggle.component.css'
11
+ })
12
+ export class JModeToggleComponent {
13
+
14
+ title = 'frontend';
15
+ theme: string = 'light';
16
+
17
+ constructor(
18
+ @Inject(PLATFORM_ID) private readonly platformId: object,
19
+ public readonly iconsService: JIconsService
20
+ ) {
21
+ this.loadTheme();
22
+ }
23
+
24
+
25
+ /**
26
+ * Set the theme for the application.
27
+ * @param theme - The theme to set, either 'light' or 'dark'.
28
+ */
29
+ setTheme(theme: 'light' | 'dark') {
30
+ if (isPlatformBrowser(this.platformId)) {
31
+ localStorage.setItem('theme', theme);
32
+ }
33
+ this.theme = theme; // Actualizar la variable theme
34
+ document.documentElement.classList.toggle('dark', theme === 'dark');
35
+ }
36
+
37
+
38
+
39
+ /**
40
+ * Load the theme from localStorage and apply it to the document.
41
+ */
42
+ loadTheme() {
43
+ if (isPlatformBrowser(this.platformId)) {
44
+ const storedTheme = localStorage.getItem('theme');
45
+ this.theme = storedTheme ?? 'light';
46
+ document.documentElement.classList.toggle('dark', this.theme === 'dark');
47
+ }
48
+ }
49
+
50
+
51
+
52
+ /**
53
+ * Toggle between light and dark mode.
54
+ */
55
+ toggleDarkMode() {
56
+ const newTheme = this.theme === 'dark' ? 'light' : 'dark';
57
+ this.setTheme(newTheme);
58
+ }
59
+
60
+
61
+ }
@@ -0,0 +1,22 @@
1
+ <div class="relative w-full flex items-center mb-2">
2
+ <progress
3
+ class="relative w-full overflow-hidden bg-slate-200 border border-border dark:border-dark-border
4
+ [&::-webkit-progress-bar]:bg-background
5
+ dark:[&::-webkit-progress-bar]:bg-dark-background
6
+ [&::-webkit-progress-value]:bg-primary
7
+ [&::-moz-progress-bar]:bg-primary
8
+ dark:[&::-webkit-progress-value]:bg-dark-primary
9
+ dark:[&::-moz-progress-bar]:bg-dark-primary
10
+ [&:disabled]:opacity-50 transition-all duration-300 ease-in-out"
11
+ [value]="value"
12
+ [max]="max"
13
+ [ngClass]="ngClasses"
14
+ [style.height.px]="height"
15
+ [style.border-radius.px]="borderRadius"
16
+ >
17
+ </progress>
18
+
19
+ <div class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 text-sm font-bold text-gray-500 dark:text-gray-400">
20
+ {{ value }}{{ simbol }}
21
+ </div>
22
+ </div>