tailjng 0.1.6 → 0.1.8

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 (175) hide show
  1. package/README.md +27 -5
  2. package/cli/execute/init-app.js +5 -2
  3. package/cli/execute/sync-app.js +14 -2
  4. package/cli/settings/colors-config-utils.js +69 -11
  5. package/cli/settings/icons-config-utils.js +62 -0
  6. package/cli/settings/path-utils.js +32 -2
  7. package/cli/settings/project-utils.js +7 -1
  8. package/cli/templates/app.generator.js +8 -5
  9. package/fesm2022/tailjng.mjs +247 -80
  10. package/fesm2022/tailjng.mjs.map +1 -1
  11. package/lib/services/static/theme.service.d.ts +39 -1
  12. package/lib/utils/theme/theme-variables.util.d.ts +31 -0
  13. package/package.json +1 -1
  14. package/public-api.d.ts +2 -1
  15. package/registry/components.json +41 -18
  16. package/src/colors.safelist.css +2 -2
  17. package/src/lib/components/.config/README.md +11 -0
  18. package/src/lib/components/.config/colors/README.md +40 -0
  19. package/src/lib/components/{colors-config → .config/colors}/colors.config.ts +5 -5
  20. package/src/lib/components/{colors-config → .config/colors}/colors.safelist.css +2 -2
  21. package/src/lib/components/.config/icons/README.md +26 -0
  22. package/src/lib/components/.config/icons/icons.lucide.ts +134 -0
  23. package/src/lib/components/.config/input/README.md +24 -0
  24. package/src/lib/components/.config/input/input.classes.ts +119 -0
  25. package/src/lib/components/alert/alert-dialog/dialog-alert.component.css +177 -6
  26. package/src/lib/components/alert/alert-dialog/dialog-alert.component.html +24 -37
  27. package/src/lib/components/alert/alert-dialog/dialog-alert.component.ts +66 -56
  28. package/src/lib/components/alert/alert-dialog/dialog-alert.types.ts +19 -0
  29. package/src/lib/components/alert/alert-toast/toast-alert.component.css +494 -14
  30. package/src/lib/components/alert/alert-toast/toast-alert.component.html +106 -102
  31. package/src/lib/components/alert/alert-toast/toast-alert.component.ts +485 -128
  32. package/src/lib/components/alert/alert-toast/toast-alert.types.ts +25 -0
  33. package/src/lib/components/badge/badge.component.html +34 -21
  34. package/src/lib/components/badge/badge.component.ts +140 -31
  35. package/src/lib/components/button/button.component.html +16 -10
  36. package/src/lib/components/button/button.component.ts +162 -22
  37. package/src/lib/components/card/card-complete/complete-card.component.html +2 -2
  38. package/src/lib/components/card/card-complete/complete-card.component.ts +26 -16
  39. package/src/lib/components/card/card-crud-complete/complete-crud-card.component.html +2 -2
  40. package/src/lib/components/card/card-crud-complete/complete-crud-card.component.ts +26 -16
  41. package/src/lib/components/checkbox/checkbox-input/input-checkbox.component.css +30 -0
  42. package/src/lib/components/checkbox/checkbox-input/input-checkbox.component.html +58 -46
  43. package/src/lib/components/checkbox/checkbox-input/input-checkbox.component.ts +135 -64
  44. package/src/lib/components/checkbox/checkbox-input/input-checkbox.types.ts +3 -0
  45. package/src/lib/components/checkbox/checkbox-switch/switch-checkbox.component.css +62 -0
  46. package/src/lib/components/checkbox/checkbox-switch/switch-checkbox.component.html +39 -25
  47. package/src/lib/components/checkbox/checkbox-switch/switch-checkbox.component.ts +74 -15
  48. package/src/lib/components/checkbox/checkbox-switch/switch-checkbox.types.ts +1 -0
  49. package/src/lib/components/coach-mark/coach-mark.component.html +6 -24
  50. package/src/lib/components/coach-mark/coach-mark.component.scss +1 -7
  51. package/src/lib/components/coach-mark/coach-mark.component.ts +51 -18
  52. package/src/lib/components/coach-mark/coach-mark.directive.ts +133 -78
  53. package/src/lib/components/coach-mark/coach-mark.types.ts +12 -0
  54. package/src/lib/components/dialog/dialog.component.css +1 -1
  55. package/src/lib/components/dialog/dialog.component.html +56 -65
  56. package/src/lib/components/dialog/dialog.component.ts +136 -110
  57. package/src/lib/components/dialog/dialog.types.ts +19 -0
  58. package/src/lib/components/filter/filter-complete/complete-filter.component.html +17 -20
  59. package/src/lib/components/filter/filter-complete/complete-filter.component.scss +25 -0
  60. package/src/lib/components/filter/filter-complete/complete-filter.component.ts +58 -34
  61. package/src/lib/components/filter/filter-complete/complete-filter.types.ts +7 -0
  62. package/src/lib/components/filter/filter-complete/complete-filter.util.ts +16 -0
  63. package/src/lib/components/form/form-container/container-form.component.css +4 -0
  64. package/src/lib/components/form/form-container/container-form.component.html +2 -2
  65. package/src/lib/components/form/form-container/container-form.component.ts +72 -16
  66. package/src/lib/components/form/form-container/container-form.types.ts +42 -0
  67. package/src/lib/components/form/form-container/form-col-span.directive.ts +25 -0
  68. package/src/lib/components/form/form-sidebar/sidebar-form.component.css +45 -0
  69. package/src/lib/components/form/form-sidebar/sidebar-form.component.html +128 -124
  70. package/src/lib/components/form/form-sidebar/sidebar-form.component.ts +114 -34
  71. package/src/lib/components/form/form-sidebar/sidebar-form.types.ts +3 -0
  72. package/src/lib/components/{toggle-radio/toggle-radio.component.css → form/form-validation/validation-form.component.css} +0 -1
  73. package/src/lib/components/form/form-validation/validation-form.component.html +10 -6
  74. package/src/lib/components/form/form-validation/validation-form.component.ts +99 -12
  75. package/src/lib/components/form/form-validation/validation-form.types.ts +33 -0
  76. package/src/lib/components/icon/icon.component.html +8 -5
  77. package/src/lib/components/icon/icon.component.ts +111 -9
  78. package/src/lib/components/input/input/input.component.css +0 -14
  79. package/src/lib/components/input/input/input.component.html +19 -16
  80. package/src/lib/components/input/input/input.component.ts +130 -53
  81. package/src/lib/components/input/input/input.types.ts +8 -0
  82. package/src/lib/components/input/input-file/file-input.component.html +65 -56
  83. package/src/lib/components/input/input-file/file-input.component.ts +276 -173
  84. package/src/lib/components/input/input-file/file-input.types.ts +2 -0
  85. package/src/lib/components/input/input-range/range-input.component.css +67 -0
  86. package/src/lib/components/input/input-range/range-input.component.html +50 -58
  87. package/src/lib/components/input/input-range/range-input.component.ts +148 -60
  88. package/src/lib/components/input/input-range/range-input.types.ts +7 -0
  89. package/src/lib/components/input/input-textarea/textarea-input.component.html +16 -7
  90. package/src/lib/components/input/input-textarea/textarea-input.component.ts +140 -50
  91. package/src/lib/components/input/input-textarea/textarea-input.types.ts +2 -0
  92. package/src/lib/components/label/label.component.html +17 -16
  93. package/src/lib/components/label/label.component.ts +94 -16
  94. package/src/lib/components/label/label.types.ts +2 -0
  95. package/src/lib/components/menu/menu-options-table/menu-options-defaults.ts +34 -0
  96. package/src/lib/components/menu/menu-options-table/options-table-menu.component.html +34 -20
  97. package/src/lib/components/menu/menu-options-table/options-table-menu.component.ts +211 -58
  98. package/src/lib/components/menu/menu-options-table/options-table-menu.types.ts +38 -0
  99. package/src/lib/components/menu/options-coach-menu/options-coach-menu.component.html +49 -52
  100. package/src/lib/components/menu/options-coach-menu/options-coach-menu.component.ts +112 -24
  101. package/src/lib/components/menu/options-coach-menu/options-coach-menu.types.ts +9 -0
  102. package/src/lib/components/mode-toggle/mode-toggle.component.html +11 -16
  103. package/src/lib/components/mode-toggle/mode-toggle.component.ts +69 -33
  104. package/src/lib/components/paginator/paginator-complete/complete-paginator.component.html +4 -4
  105. package/src/lib/components/paginator/paginator-complete/complete-paginator.component.ts +31 -7
  106. package/src/lib/components/paginator/paginator-complete/complete-paginator.types.ts +12 -0
  107. package/src/lib/components/paginator/paginator-complete/complete-paginator.util.ts +36 -0
  108. package/src/lib/components/progress-bar/progress-bar.component.html +41 -40
  109. package/src/lib/components/progress-bar/progress-bar.component.ts +95 -11
  110. package/src/lib/components/progress-bar/progress-bar.types.ts +2 -0
  111. package/src/lib/components/select/select-dropdown/dropdown-select.component.html +56 -46
  112. package/src/lib/components/select/select-dropdown/dropdown-select.component.ts +450 -509
  113. package/src/lib/components/select/select-dropdown/dropdown-select.types.ts +43 -0
  114. package/src/lib/components/select/select-dropdown/dropdown-select.util.ts +179 -0
  115. package/src/lib/components/select/select-multi-dropdown/multi-dropdown-select.component.html +131 -42
  116. package/src/lib/components/select/select-multi-dropdown/multi-dropdown-select.component.ts +491 -475
  117. package/src/lib/components/select/select-multi-dropdown/multi-dropdown-select.types.ts +22 -0
  118. package/src/lib/components/select/select-multi-dropdown/multi-dropdown-select.util.ts +20 -0
  119. package/src/lib/components/select/select-multi-table/multi-table-select.component.css +4 -0
  120. package/src/lib/components/select/select-multi-table/multi-table-select.component.html +76 -60
  121. package/src/lib/components/select/select-multi-table/multi-table-select.component.ts +250 -313
  122. package/src/lib/components/select/select-multi-table/multi-table-select.types.ts +10 -0
  123. package/src/lib/components/select/select-multi-table/multi-table-select.util.ts +5 -0
  124. package/src/lib/components/sidebar/sidebar-static/static-sidebar.component.css +155 -0
  125. package/src/lib/components/sidebar/sidebar-static/static-sidebar.component.html +72 -53
  126. package/src/lib/components/sidebar/sidebar-static/static-sidebar.component.ts +84 -27
  127. package/src/lib/components/sidebar/sidebar-static/static-sidebar.types.ts +2 -0
  128. package/src/lib/components/table/table-complete/complete-table.component.html +21 -23
  129. package/src/lib/components/table/table-complete/complete-table.component.ts +190 -338
  130. package/src/lib/components/table/table-complete/complete-table.types.ts +28 -0
  131. package/src/lib/components/table/table-complete/complete-table.util.ts +236 -0
  132. package/src/lib/components/table/table-complete/index.ts +2 -0
  133. package/src/lib/components/table/table-crud-complete/complete-crud-table.animations.ts +34 -0
  134. package/src/lib/components/table/table-crud-complete/complete-crud-table.component.html +87 -142
  135. package/src/lib/components/table/table-crud-complete/complete-crud-table.component.scss +0 -63
  136. package/src/lib/components/table/table-crud-complete/complete-crud-table.component.ts +544 -831
  137. package/src/lib/components/table/table-crud-complete/complete-crud-table.types.ts +57 -0
  138. package/src/lib/components/table/table-crud-complete/complete-crud-table.util.ts +723 -0
  139. package/src/lib/components/table/table-crud-complete/index.ts +3 -0
  140. package/src/lib/components/theme-generator/theme-generator.component.css +21 -0
  141. package/src/lib/components/theme-generator/theme-generator.component.html +141 -116
  142. package/src/lib/components/theme-generator/theme-generator.component.ts +44 -24
  143. package/src/lib/components/toggle-radio/shared/toggle-options.types.ts +8 -0
  144. package/src/lib/components/toggle-radio/shared/toggle-options.util.ts +62 -0
  145. package/src/lib/components/toggle-radio/toggle-radio/toggle-radio.component.css +22 -0
  146. package/src/lib/components/toggle-radio/toggle-radio/toggle-radio.component.html +65 -0
  147. package/src/lib/components/toggle-radio/toggle-radio/toggle-radio.component.ts +192 -0
  148. package/src/lib/components/toggle-radio/toggle-radio/toggle-radio.types.ts +1 -0
  149. package/src/lib/components/toggle-radio/toggle-segment/segment-toggle.component.css +34 -0
  150. package/src/lib/components/toggle-radio/toggle-segment/segment-toggle.component.html +47 -0
  151. package/src/lib/components/toggle-radio/toggle-segment/segment-toggle.component.ts +187 -0
  152. package/src/lib/components/toggle-radio/toggle-segment/segment-toggle.types.ts +1 -0
  153. package/src/lib/components/tooltip/tooltip.directive.ts +12 -9
  154. package/src/lib/components/tooltip/tooltip.service.ts +331 -133
  155. package/src/lib/components/tooltip/tooltip.types.ts +9 -0
  156. package/src/lib/components/viewer/viewer-image/image-viewer.component.css +14 -4
  157. package/src/lib/components/viewer/viewer-image/image-viewer.component.html +61 -95
  158. package/src/lib/components/viewer/viewer-image/image-viewer.component.ts +182 -177
  159. package/src/lib/components/viewer/viewer-image/image-viewer.types.ts +3 -0
  160. package/src/lib/components/viewer/viewer-pdf/pdf-viewer.component.css +25 -0
  161. package/src/lib/components/viewer/viewer-pdf/pdf-viewer.component.html +95 -24
  162. package/src/lib/components/viewer/viewer-pdf/pdf-viewer.component.ts +168 -15
  163. package/src/lib/components/viewer/viewer-pdf/pdf-viewer.types.ts +1 -0
  164. package/src/styles.css +2 -2
  165. package/lib/services/static/icons.service.d.ts +0 -65
  166. package/src/lib/components/colors-config/README.md +0 -38
  167. package/src/lib/components/form/form-sidebar/sidebar-form.component.scss +0 -0
  168. package/src/lib/components/form/form-validation/validation-form.component.scss +0 -0
  169. package/src/lib/components/menu/menu-options-table/options-table-menu.component.scss +0 -0
  170. package/src/lib/components/menu/options-coach-menu/options-coach-menu.component.scss +0 -12
  171. package/src/lib/components/sidebar/sidebar-static/static-sidebar.component.scss +0 -0
  172. package/src/lib/components/toggle-radio/toggle-radio.component.html +0 -51
  173. package/src/lib/components/toggle-radio/toggle-radio.component.ts +0 -222
  174. package/src/lib/components/viewer/viewer-pdf/pdf-viewer.component.scss +0 -0
  175. package/tailjng-0.1.6.tgz +0 -0
@@ -1,3 +1,6 @@
1
+ export * from './complete-crud-table.animations';
2
+ export * from './complete-crud-table.types';
3
+ export * from './complete-crud-table.util';
1
4
  export * from './expand-grid/table-expand-grid.builder';
2
5
  export * from './expand-grid/table-expand-grid.helper';
3
6
  export * from './expand-grid/table-expand-grid.types';
@@ -0,0 +1,21 @@
1
+ @keyframes theme-save-pop {
2
+ 0% {
3
+ transform: scale(1);
4
+ box-shadow: none;
5
+ }
6
+
7
+ 35% {
8
+ transform: scale(1.35);
9
+ box-shadow: 0 0 0 4px color-mix(in srgb, var(--color-primary) 40%, transparent);
10
+ }
11
+
12
+ 100% {
13
+ transform: scale(1);
14
+ box-shadow: none;
15
+ }
16
+ }
17
+
18
+ :host ::ng-deep button.theme-save-applied {
19
+ animation: theme-save-pop 0.65s cubic-bezier(0.34, 1.56, 0.64, 1);
20
+ color: var(--color-primary);
21
+ }
@@ -1,123 +1,148 @@
1
1
  <main class="container mx-auto">
2
- <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
3
-
4
- <!-- Controls Panel -->
5
- <div class="space-y-8 select-none">
6
-
7
- <div>
8
- <h2 class="text-sm font-bold mb-1 opacity-60">Selector de color</h2>
9
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
10
-
11
- <!-- Color Picker -->
12
- <div class="relative h-64 w-full overflow-hidden rounded-lg border border-border dark:border-dark-border">
13
- <div class="absolute inset-0 bg-gradient-to-br from-white to-transparent" style="z-index: 1;"></div>
14
- <div class="absolute inset-0 bg-gradient-to-b from-transparent to-black" style="z-index: 2;"></div>
15
- <div class="absolute inset-0" [style.background]="'linear-gradient(to right, hsl(' + huePosition + ', 0%, 50%), hsl(' + huePosition + ', 100%, 50%))'" style="z-index: 0;"></div>
16
- <div class="absolute w-6 h-6 rounded-full border-2 border-white transform -translate-x-1/2 -translate-y-1/2 cursor-pointer" [style.left.%]="colorPickerPosition.x" [style.top.%]="colorPickerPosition.y" style="z-index: 3;"></div>
17
- <div class="absolute inset-0 cursor-pointer" (mousedown)="startColorPicking($event)" (mousemove)="updateColorPicking($event)" (mouseup)="stopColorPicking()" (mouseleave)="stopColorPicking()" style="z-index: 4;"></div>
18
- </div>
19
-
20
- <!-- Color Spectrum -->
21
- <div class="space-y-4">
22
- <div class="relative">
23
-
24
- <!-- Picker bar -->
25
- <div class="h-8 w-full rounded-lg overflow-hidden border border-border dark:border-dark-border relative">
26
- <div class="absolute inset-0" [style.background]="hueGradient"></div>
27
-
28
- <input
29
- type="range"
30
- min="0"
31
- max="360"
32
- [value]="huePosition"
33
- (input)="updateHueFromInput($event)"
34
- class="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
35
- />
36
- </div>
37
-
38
- <!-- Ball outside the flow to stand out -->
39
- <div class="absolute top-1/2 transform -translate-y-1/2 -translate-x-1/2 w-9 h-9 rounded-full border-2 border-white z-10 pointer-events-none"
40
- [style.left.%]="(huePosition / 360) * 100"
41
- [style.backgroundColor]="hslToHex(huePosition, 100, 50)">
42
- </div>
43
-
44
- </div>
45
-
46
-
47
- <!-- Hex Input -->
48
- <JFormContainer>
49
- <JFormContainer>
50
- <JLabel for="baseColor" classes="opacity-60">Ingresa un valor Hex</JLabel>
51
-
52
- <JFormContainer [rows]="true">
53
-
54
- <JFormContainer class="flex-1">
55
- <JInput
56
- id="baseColor"
57
- type="text"
58
- [(ngModel)]="baseColor"
59
- (input)="updateFromHexInput()"
60
- placeholder="#000000"
61
- />
62
- </JFormContainer>
63
-
64
- <!-- Color Preview -->
65
- <div class="h-[35px] w-[60px] rounded shadow-md" [style.background-color]="baseColor"></div>
66
-
67
- </JFormContainer>
68
- </JFormContainer>
69
-
70
- <!-- Saturation Slider -->
71
- <JRangeInput
72
- [min]="0"
73
- [max]="100"
74
- [(ngModel)]="saturation"
75
- (input)="generateTheme()"
76
- placeholder="Saturación"
77
- [isLabel]="true"
78
- simbol="%"
79
- />
80
-
81
- <!-- Lightness Slider -->
82
- <JRangeInput
83
- [min]="0"
84
- [max]="100"
85
- [(ngModel)]="lightness"
86
- (input)="generateTheme()"
87
- placeholder="Luminosidad"
88
- [isLabel]="true"
89
- simbol="%"
90
- />
91
-
92
- </JFormContainer>
93
-
94
- </div>
95
- </div>
96
-
97
- </div>
98
- </div>
99
-
100
- <!-- Code Preview -->
101
- <div class="relative">
2
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
3
+ <!-- Controls Panel -->
4
+ <div class="space-y-8 select-none">
5
+ <div>
6
+ <h2 class="text-sm font-bold mb-1 opacity-60">Selector de color</h2>
7
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
8
+ <!-- Color Picker -->
9
+ <div
10
+ class="relative h-64 w-full overflow-hidden rounded-lg border border-border dark:border-dark-border"
11
+ >
102
12
  <div
103
- class="h-70 bg-background dark:bg-dark-background text-black dark:text-white overflow-auto rounded-lg font-mono text-sm whitespace-pre-wrap border border-border dark:border-dark-border scroll-element">
104
- <div class="p-4">
105
- <span>{{ themeCode }}</span>
106
- </div>
107
- </div>
108
-
109
- <div class="absolute top-4 right-4">
110
- <JButton
111
- (clicked)="copyThemeToClipboard()"
112
- [icon]="iconsService.icons.copy"
113
- [iconChange]="iconsService.icons.check"
114
- [isChangeIcon]="copied"
115
- [iconSize]="15"
116
- tooltip="Copiar"
117
- classes="w-[25px] h-[25px]"
13
+ class="absolute inset-0 z-[1] bg-gradient-to-br from-white to-transparent"
14
+ ></div>
15
+ <div
16
+ class="absolute inset-0 z-[2] bg-gradient-to-b from-transparent to-black"
17
+ ></div>
18
+ <div
19
+ class="absolute inset-0 z-0"
20
+ [style.background]="
21
+ 'linear-gradient(to right, hsl(' +
22
+ huePosition +
23
+ ', 0%, 50%), hsl(' +
24
+ huePosition +
25
+ ', 100%, 50%))'
26
+ "
27
+ ></div>
28
+ <div
29
+ class="absolute z-[3] w-6 h-6 rounded-full border-2 border-white transform -translate-x-1/2 -translate-y-1/2 cursor-pointer"
30
+ [style.left.%]="colorPickerPosition.x"
31
+ [style.top.%]="colorPickerPosition.y"
32
+ ></div>
33
+ <div
34
+ class="absolute inset-0 z-[4] cursor-pointer"
35
+ (mousedown)="startColorPicking($event)"
36
+ (mousemove)="updateColorPicking($event)"
37
+ (mouseup)="stopColorPicking()"
38
+ (mouseleave)="stopColorPicking()"
39
+ ></div>
40
+ </div>
41
+
42
+ <!-- Color Spectrum -->
43
+ <div class="space-y-4">
44
+ <div class="relative">
45
+ <!-- Picker bar -->
46
+ <div
47
+ class="h-8 w-full rounded-lg overflow-hidden border border-border dark:border-dark-border relative"
48
+ >
49
+ <div
50
+ class="absolute inset-0"
51
+ [style.background]="hueGradient"
52
+ ></div>
53
+
54
+ <input
55
+ type="range"
56
+ min="0"
57
+ max="360"
58
+ [value]="huePosition"
59
+ (input)="updateHueFromInput($event)"
60
+ class="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
118
61
  />
62
+ </div>
63
+
64
+ <!-- Ball outside the flow to stand out -->
65
+ <div
66
+ class="absolute top-1/2 transform -translate-y-1/2 -translate-x-1/2 w-9 h-9 rounded-full border-2 border-white z-10 pointer-events-none"
67
+ [style.left.%]="(huePosition / 360) * 100"
68
+ [style.backgroundColor]="hslToHex(huePosition, 100, 50)"
69
+ ></div>
119
70
  </div>
71
+
72
+ <!-- Hex Input -->
73
+ <JFormContainer>
74
+ <JFormContainer>
75
+ <JLabel for="baseColor" classes="opacity-60"
76
+ >Ingresa un valor Hex</JLabel
77
+ >
78
+
79
+ <JFormContainer [rows]="true" [gap]="3">
80
+ <JFormContainer class="flex-1">
81
+ <JInput
82
+ id="baseColor"
83
+ type="text"
84
+ [(ngModel)]="baseColor"
85
+ (input)="updateFromHexInput()"
86
+ placeholder="#000000"
87
+ />
88
+ </JFormContainer>
89
+
90
+ <!-- Color Preview -->
91
+ <div
92
+ class="h-[35px] w-[60px] rounded shadow-md"
93
+ [style.background-color]="baseColor"
94
+ ></div>
95
+ </JFormContainer>
96
+ </JFormContainer>
97
+
98
+ <!-- Saturation Slider -->
99
+ <JRangeInput
100
+ [min]="0"
101
+ [max]="100"
102
+ [(ngModel)]="saturation"
103
+ (input)="generateTheme()"
104
+ placeholder="Saturación"
105
+ [isLabel]="true"
106
+ simbol="%"
107
+ />
108
+
109
+ <!-- Lightness Slider -->
110
+ <JRangeInput
111
+ [min]="0"
112
+ [max]="100"
113
+ [(ngModel)]="lightness"
114
+ (input)="generateTheme()"
115
+ placeholder="Luminosidad"
116
+ [isLabel]="true"
117
+ simbol="%"
118
+ />
119
+ </JFormContainer>
120
+ </div>
120
121
  </div>
122
+ </div>
123
+ </div>
121
124
 
125
+ <!-- Code Preview -->
126
+ <div class="relative">
127
+ <div
128
+ class="h-70 bg-background dark:bg-dark-background text-black dark:text-white overflow-auto rounded-lg font-mono text-sm whitespace-pre-wrap border border-border dark:border-dark-border scroll-element"
129
+ >
130
+ <div class="p-4">
131
+ <span>{{ themeCode }}</span>
132
+ </div>
133
+ </div>
134
+
135
+ <div class="absolute top-4 right-4 flex gap-1">
136
+ <JButton
137
+ (clicked)="copyThemeToClipboard()"
138
+ [icon]="Icons.Copy"
139
+ [iconChange]="Icons.Check"
140
+ [isChangeIcon]="copied"
141
+ [iconSize]="15"
142
+ tooltip="Copiar"
143
+ classes="w-[25px] h-[25px]"
144
+ />
145
+ </div>
122
146
  </div>
123
- </main>
147
+ </div>
148
+ </main>
@@ -1,20 +1,20 @@
1
- import { Component } from '@angular/core';
1
+ import { Component, OnDestroy, OnInit, effect } from '@angular/core';
2
2
  import { FormsModule } from '@angular/forms';
3
- import { LucideAngularModule } from 'lucide-angular';
4
3
  import { JInputComponent } from '../input/input/input.component';
5
4
  import { JRangeInputComponent } from '../input/input-range/range-input.component';
6
5
  import { JButtonComponent } from '../button/button.component';
7
6
  import { JLabelComponent } from '../label/label.component';
8
- import { ColorPosition, GeneratedColors, JIconsService, JThemeService, ThemeMode } from 'tailjng';
7
+ import { ColorPosition, GeneratedColors, JThemeService, ThemeMode, applyGeneratedColorsToDocument, clearGeneratedColorsFromDocument } from 'tailjng';
9
8
  import { JFormContainerComponent } from '../form/form-container/container-form.component';
9
+ import { Icons } from '../.config/icons/icons.lucide';
10
10
 
11
11
  @Component({
12
12
  selector: 'JThemeGenerator',
13
- imports: [LucideAngularModule, JInputComponent, JRangeInputComponent, JButtonComponent, FormsModule, JLabelComponent, JFormContainerComponent],
13
+ imports: [JInputComponent, JRangeInputComponent, JButtonComponent, FormsModule, JLabelComponent, JFormContainerComponent],
14
14
  templateUrl: './theme-generator.component.html',
15
- styleUrl: './theme-generator.component.css'
16
15
  })
17
- export class JThemeGeneratorComponent {
16
+ export class JThemeGeneratorComponent implements OnInit, OnDestroy {
17
+ readonly Icons = Icons;
18
18
 
19
19
  // Color picker state
20
20
  baseColor: string = '#415884';
@@ -48,22 +48,27 @@ export class JThemeGeneratorComponent {
48
48
  }
49
49
 
50
50
  constructor(
51
- public readonly iconsService: JIconsService,
52
51
  public readonly themeService: JThemeService
53
- ) { }
52
+ ) {
53
+ effect(() => {
54
+ this.themeService.themeSignal();
55
+ if (this.generatedColors) {
56
+ this.applyColorsToApp(this.generatedColors);
57
+ }
58
+ });
59
+ }
54
60
 
55
- ngOnInit() {
56
- this.syncFromHSL();
61
+ ngOnDestroy(): void {
62
+ if (typeof this.themeService.clearPreviewColors === 'function') {
63
+ this.themeService.clearPreviewColors();
64
+ return;
65
+ }
57
66
 
58
- // Asynchronously check for theme changes every 300ms
59
- setInterval(() => {
60
- const current = localStorage.getItem('theme') as ThemeMode;
61
- if (current && current !== this.lastTheme) {
62
- this.previewMode = current;
63
- this.lastTheme = current;
64
- this.generateTheme();
65
- }
66
- }, 300);
67
+ clearGeneratedColorsFromDocument();
68
+ }
69
+
70
+ ngOnInit() {
71
+ this.syncFromHSL(false);
67
72
  }
68
73
 
69
74
 
@@ -179,9 +184,9 @@ export class JThemeGeneratorComponent {
179
184
  /**
180
185
  * Sync the internal state from HSL values.
181
186
  */
182
- syncFromHSL(): void {
187
+ syncFromHSL(applyToApp = true): void {
183
188
  this.baseColor = this.hslToHex(this.huePosition, this.saturation, this.lightness);
184
- this.generateTheme();
189
+ this.generateTheme(applyToApp);
185
190
  }
186
191
 
187
192
 
@@ -251,7 +256,7 @@ export class JThemeGeneratorComponent {
251
256
  /**
252
257
  * Generate the theme colors.
253
258
  */
254
- generateTheme(): void {
259
+ generateTheme(applyToApp = true): void {
255
260
  this.baseColor = this.hslToHex(this.huePosition, this.saturation * 0.9, this.lightness);
256
261
 
257
262
  const vars = this.generatedColors = {
@@ -298,8 +303,7 @@ export class JThemeGeneratorComponent {
298
303
  darkDestructiveForeground: this.hslToHex(this.huePosition, this.saturation * 0.2, 90),
299
304
  darkBorder: this.hslToHex(this.huePosition, this.saturation * 0.5, 45),
300
305
  darkInput: this.hslToHex(this.huePosition, this.saturation * 0.5, 45),
301
- darkRing: this.hslToHex(this.huePosition, this.saturation * 0.7, 28),
302
- };
306
+ darkRing: this.hslToHex(this.huePosition, this.saturation * 0.7, 28)};
303
307
 
304
308
  const toCssVar = (key: string, value: string) =>
305
309
  ` --color-${key.replace(/[A-Z]/g, m => '-' + m.toLowerCase())}: ${value};`;
@@ -320,8 +324,24 @@ export class JThemeGeneratorComponent {
320
324
  lines.push(` --color-dark-radius: 0.5rem;`);
321
325
 
322
326
  this.themeCode = `@theme {\n${lines.join('\n')}\n}`;
327
+
328
+ if (applyToApp) {
329
+ this.applyColorsToApp(vars);
330
+ }
323
331
  }
324
332
 
333
+ /**
334
+ * Applies palette CSS variables to the whole app.
335
+ * @param colors Generated palette.
336
+ */
337
+ private applyColorsToApp(colors: GeneratedColors): void {
338
+ if (typeof this.themeService.applyPreviewColors === 'function') {
339
+ this.themeService.applyPreviewColors(colors);
340
+ return;
341
+ }
342
+
343
+ applyGeneratedColorsToDocument(colors);
344
+ }
325
345
 
326
346
  copyThemeToClipboard(): void {
327
347
  navigator.clipboard.writeText(this.themeCode);
@@ -0,0 +1,8 @@
1
+ export type ToggleOption<T = unknown> = {
2
+ value: T;
3
+ label: string;
4
+ };
5
+
6
+ export type ToggleSortOrder = 'ASC' | 'DESC';
7
+
8
+ export type ToggleRadioLayout = 'vertical' | 'horizontal';
@@ -0,0 +1,62 @@
1
+ import { ToggleOption, ToggleSortOrder } from './toggle-options.types';
2
+
3
+ /**
4
+ * Query params for toggle API loads (`findAll`).
5
+ * Arrays are kept as arrays so `JParamsHttpService` serializes them as
6
+ * `filter[key][0]`, `filter[key][1]`, …
7
+ */
8
+ export function buildToggleLoadParams(
9
+ sort: ToggleSortOrder,
10
+ defaultFilters: Record<string, unknown>,
11
+ ): Record<string, unknown> {
12
+ const params: Record<string, unknown> = { sortOrder: sort };
13
+
14
+ Object.keys(defaultFilters).forEach((key) => {
15
+ params[`filter[${key}]`] = defaultFilters[key];
16
+ });
17
+
18
+ return params;
19
+ }
20
+
21
+ /**
22
+ * Reads a nested property using dot notation.
23
+ */
24
+ export function getNestedToggleValue(obj: unknown, path: string): string {
25
+ if (!obj || typeof obj !== 'object') {
26
+ return '';
27
+ }
28
+
29
+ const value = path.split('.').reduce<unknown>((acc, part) => {
30
+ if (acc && typeof acc === 'object' && part in (acc as Record<string, unknown>)) {
31
+ return (acc as Record<string, unknown>)[part];
32
+ }
33
+ return undefined;
34
+ }, obj);
35
+
36
+ return value == null ? '' : String(value);
37
+ }
38
+
39
+ /**
40
+ * Normalizes static options into `{ value, label }` pairs.
41
+ */
42
+ export function normalizeToggleOptions(
43
+ options: unknown[],
44
+ optionLabel: string,
45
+ optionValue: string,
46
+ ): ToggleOption[] {
47
+ if (!options.length) {
48
+ return [];
49
+ }
50
+
51
+ if (typeof options[0] === 'object' && options[0] !== null) {
52
+ return options.map((opt) => ({
53
+ value: (opt as Record<string, unknown>)[optionValue],
54
+ label: getNestedToggleValue(opt, optionLabel),
55
+ }));
56
+ }
57
+
58
+ return options.map((opt) => ({
59
+ value: opt,
60
+ label: String(opt),
61
+ }));
62
+ }
@@ -0,0 +1,22 @@
1
+ :host {
2
+ display: block;
3
+ width: 100%;
4
+ }
5
+
6
+ .j-radio-group--horizontal {
7
+ flex-flow: row wrap;
8
+ gap: 1rem 1.25rem;
9
+ }
10
+
11
+ .j-radio-group--disabled {
12
+ opacity: 0.55;
13
+ }
14
+
15
+ .j-radio-option--disabled {
16
+ cursor: not-allowed;
17
+ }
18
+
19
+ .j-radio-input:focus-visible + .j-radio-indicator {
20
+ outline: 2px solid var(--color-ring);
21
+ outline-offset: 2px;
22
+ }
@@ -0,0 +1,65 @@
1
+ @if (internalOptions.length > 0) {
2
+ <div [ngClass]="groupClasses" role="radiogroup" class="flex flex-col gap-2.5">
3
+ @for (opt of internalOptions; track $index) {
4
+ <label
5
+ class="j-radio-option inline-flex items-center gap-2.5 cursor-pointer select-none"
6
+ [class.j-radio-option--selected]="isSelected(opt.value)"
7
+ [class.j-radio-option--disabled]="isInteractionDisabled"
8
+ [for]="optionId(opt.value, $index)"
9
+ >
10
+ <input
11
+ class="j-radio-input absolute opacity-0 w-0 h-0 m-0 pointer-events-none"
12
+ type="radio"
13
+ [id]="optionId(opt.value, $index)"
14
+ [name]="name"
15
+ [value]="opt.value"
16
+ [checked]="isSelected(opt.value)"
17
+ [disabled]="isInteractionDisabled"
18
+ (change)="select(opt.value)"
19
+ />
20
+
21
+ <span
22
+ class="j-radio-indicator inline-flex items-center justify-center w-[1.125rem] h-[1.125rem] shrink-0 border-[1.5px] rounded-full bg-background dark:bg-dark-background transition-[border-color,background-color] duration-150 ease-in-out"
23
+ [ngClass]="{
24
+ 'border-primary dark:border-dark-primary': isSelected(opt.value),
25
+ 'border-border dark:border-dark-border': !isSelected(opt.value),
26
+ }"
27
+ aria-hidden="true"
28
+ >
29
+ <span
30
+ class="j-radio-dot w-[0.4375rem] h-[0.4375rem] rounded-full bg-primary dark:bg-dark-primary transition-transform duration-150 ease-in-out"
31
+ [class.scale-0]="!isSelected(opt.value)"
32
+ [class.scale-100]="isSelected(opt.value)"
33
+ ></span>
34
+ </span>
35
+
36
+ <span class="text-sm leading-[1.35] text-foreground dark:text-dark-foreground">{{ opt.label }}</span>
37
+ </label>
38
+ }
39
+ </div>
40
+ } @else if (isLoading) {
41
+ <div class="flex items-center justify-start gap-2 min-h-8 text-muted-foreground dark:text-dark-muted-foreground text-sm">
42
+ <JIcon
43
+ [icon]="Icons.Loader2"
44
+ [size]="16"
45
+ iconClass="animate-spin text-muted-foreground"
46
+ [ariaHidden]="true"
47
+ />
48
+ <span>Cargando...</span>
49
+ </div>
50
+ } @else {
51
+ <div class="flex items-center justify-start gap-2 min-h-8 text-muted-foreground dark:text-dark-muted-foreground text-sm">
52
+ No hay opciones
53
+ </div>
54
+ }
55
+
56
+ @if (showClear && selectedValue !== null) {
57
+ <button
58
+ type="button"
59
+ class="mt-2.5 p-0 border-0 bg-transparent text-destructive text-xs underline cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed"
60
+ (click)="clear()"
61
+ [disabled]="isInteractionDisabled"
62
+ >
63
+ Limpiar selección
64
+ </button>
65
+ }