tailjng 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -4
- package/cli/execute/init-app.js +5 -2
- package/cli/execute/sync-app.js +14 -2
- package/cli/settings/colors-config-utils.js +43 -8
- package/cli/settings/icons-config-utils.js +62 -0
- package/cli/settings/path-utils.js +32 -2
- package/cli/settings/project-utils.js +7 -1
- package/cli/templates/app.generator.js +2 -2
- package/fesm2022/tailjng.mjs +247 -80
- package/fesm2022/tailjng.mjs.map +1 -1
- package/lib/services/static/theme.service.d.ts +39 -1
- package/lib/utils/theme/theme-variables.util.d.ts +31 -0
- package/package.json +1 -1
- package/public-api.d.ts +2 -1
- package/registry/components.json +41 -18
- package/src/colors.safelist.css +2 -2
- package/src/lib/components/.config/README.md +11 -0
- package/src/lib/components/.config/colors/README.md +38 -0
- package/src/lib/components/{colors-config → .config/colors}/colors.config.ts +5 -5
- package/src/lib/components/{colors-config → .config/colors}/colors.safelist.css +2 -2
- package/src/lib/components/.config/icons/README.md +26 -0
- package/src/lib/components/.config/icons/icons.lucide.ts +134 -0
- package/src/lib/components/.config/input/README.md +24 -0
- package/src/lib/components/.config/input/input.classes.ts +119 -0
- package/src/lib/components/alert/alert-dialog/dialog-alert.component.css +244 -2
- package/src/lib/components/alert/alert-dialog/dialog-alert.component.html +25 -38
- package/src/lib/components/alert/alert-dialog/dialog-alert.component.ts +66 -56
- package/src/lib/components/alert/alert-dialog/dialog-alert.types.ts +19 -0
- package/src/lib/components/alert/alert-toast/toast-alert.component.css +630 -12
- package/src/lib/components/alert/alert-toast/toast-alert.component.html +103 -102
- package/src/lib/components/alert/alert-toast/toast-alert.component.ts +485 -128
- package/src/lib/components/alert/alert-toast/toast-alert.types.ts +25 -0
- package/src/lib/components/badge/badge.component.html +34 -21
- package/src/lib/components/badge/badge.component.ts +140 -31
- package/src/lib/components/button/button.component.html +16 -10
- package/src/lib/components/button/button.component.ts +162 -22
- package/src/lib/components/card/card-complete/complete-card.component.html +2 -2
- package/src/lib/components/card/card-complete/complete-card.component.ts +26 -16
- package/src/lib/components/card/card-crud-complete/complete-crud-card.component.html +2 -2
- package/src/lib/components/card/card-crud-complete/complete-crud-card.component.ts +26 -16
- package/src/lib/components/checkbox/checkbox-input/input-checkbox.component.css +97 -0
- package/src/lib/components/checkbox/checkbox-input/input-checkbox.component.html +54 -46
- package/src/lib/components/checkbox/checkbox-input/input-checkbox.component.ts +135 -64
- package/src/lib/components/checkbox/checkbox-input/input-checkbox.types.ts +3 -0
- package/src/lib/components/checkbox/checkbox-switch/switch-checkbox.component.css +112 -0
- package/src/lib/components/checkbox/checkbox-switch/switch-checkbox.component.html +28 -25
- package/src/lib/components/checkbox/checkbox-switch/switch-checkbox.component.ts +67 -15
- package/src/lib/components/checkbox/checkbox-switch/switch-checkbox.types.ts +1 -0
- package/src/lib/components/coach-mark/coach-mark.component.html +4 -22
- package/src/lib/components/coach-mark/coach-mark.component.scss +1 -1
- package/src/lib/components/coach-mark/coach-mark.component.ts +51 -18
- package/src/lib/components/coach-mark/coach-mark.directive.ts +133 -78
- package/src/lib/components/coach-mark/coach-mark.types.ts +12 -0
- package/src/lib/components/dialog/dialog.component.css +103 -1
- package/src/lib/components/dialog/dialog.component.html +46 -66
- package/src/lib/components/dialog/dialog.component.ts +136 -110
- package/src/lib/components/dialog/dialog.types.ts +19 -0
- package/src/lib/components/filter/filter-complete/complete-filter.component.html +16 -19
- package/src/lib/components/filter/filter-complete/complete-filter.component.scss +35 -0
- package/src/lib/components/filter/filter-complete/complete-filter.component.ts +58 -34
- package/src/lib/components/filter/filter-complete/complete-filter.types.ts +7 -0
- package/src/lib/components/filter/filter-complete/complete-filter.util.ts +16 -0
- package/src/lib/components/form/form-container/container-form.component.css +4 -0
- package/src/lib/components/form/form-container/container-form.component.html +2 -2
- package/src/lib/components/form/form-container/container-form.component.ts +72 -16
- package/src/lib/components/form/form-container/container-form.types.ts +42 -0
- package/src/lib/components/form/form-container/form-col-span.directive.ts +25 -0
- package/src/lib/components/form/form-sidebar/sidebar-form.component.css +276 -0
- package/src/lib/components/form/form-sidebar/sidebar-form.component.html +117 -125
- package/src/lib/components/form/form-sidebar/sidebar-form.component.ts +109 -34
- package/src/lib/components/form/form-sidebar/sidebar-form.types.ts +3 -0
- package/src/lib/components/{toggle-radio/toggle-radio.component.css → form/form-validation/validation-form.component.css} +0 -1
- package/src/lib/components/form/form-validation/validation-form.component.html +10 -6
- package/src/lib/components/form/form-validation/validation-form.component.ts +99 -12
- package/src/lib/components/form/form-validation/validation-form.types.ts +33 -0
- package/src/lib/components/icon/icon.component.html +8 -5
- package/src/lib/components/icon/icon.component.ts +111 -9
- package/src/lib/components/input/input/input.component.html +19 -16
- package/src/lib/components/input/input/input.component.ts +130 -53
- package/src/lib/components/input/input/input.types.ts +8 -0
- package/src/lib/components/input/input-file/file-input.component.html +65 -56
- package/src/lib/components/input/input-file/file-input.component.ts +276 -173
- package/src/lib/components/input/input-file/file-input.types.ts +2 -0
- package/src/lib/components/input/input-range/range-input.component.css +67 -0
- package/src/lib/components/input/input-range/range-input.component.html +50 -58
- package/src/lib/components/input/input-range/range-input.component.ts +148 -60
- package/src/lib/components/input/input-range/range-input.types.ts +7 -0
- package/src/lib/components/input/input-textarea/textarea-input.component.html +16 -7
- package/src/lib/components/input/input-textarea/textarea-input.component.ts +140 -50
- package/src/lib/components/input/input-textarea/textarea-input.types.ts +2 -0
- package/src/lib/components/label/label.component.html +17 -16
- package/src/lib/components/label/label.component.ts +70 -16
- package/src/lib/components/label/label.types.ts +2 -0
- package/src/lib/components/menu/menu-options-table/menu-options-defaults.ts +34 -0
- package/src/lib/components/menu/menu-options-table/options-table-menu.component.html +34 -20
- package/src/lib/components/menu/menu-options-table/options-table-menu.component.ts +211 -58
- package/src/lib/components/menu/menu-options-table/options-table-menu.types.ts +38 -0
- package/src/lib/components/menu/options-coach-menu/options-coach-menu.component.html +49 -52
- package/src/lib/components/menu/options-coach-menu/options-coach-menu.component.ts +112 -24
- package/src/lib/components/menu/options-coach-menu/options-coach-menu.types.ts +9 -0
- package/src/lib/components/mode-toggle/mode-toggle.component.html +11 -16
- package/src/lib/components/mode-toggle/mode-toggle.component.ts +69 -33
- package/src/lib/components/paginator/paginator-complete/complete-paginator.component.html +4 -4
- package/src/lib/components/paginator/paginator-complete/complete-paginator.component.ts +31 -7
- package/src/lib/components/paginator/paginator-complete/complete-paginator.types.ts +12 -0
- package/src/lib/components/paginator/paginator-complete/complete-paginator.util.ts +36 -0
- package/src/lib/components/progress-bar/progress-bar.component.css +11 -0
- package/src/lib/components/progress-bar/progress-bar.component.html +41 -40
- package/src/lib/components/progress-bar/progress-bar.component.ts +95 -11
- package/src/lib/components/progress-bar/progress-bar.types.ts +2 -0
- package/src/lib/components/select/select-dropdown/dropdown-select.component.css +6 -0
- package/src/lib/components/select/select-dropdown/dropdown-select.component.html +54 -44
- package/src/lib/components/select/select-dropdown/dropdown-select.component.ts +450 -509
- package/src/lib/components/select/select-dropdown/dropdown-select.types.ts +43 -0
- package/src/lib/components/select/select-dropdown/dropdown-select.util.ts +179 -0
- package/src/lib/components/select/select-multi-dropdown/multi-dropdown-select.component.css +6 -0
- package/src/lib/components/select/select-multi-dropdown/multi-dropdown-select.component.html +131 -42
- package/src/lib/components/select/select-multi-dropdown/multi-dropdown-select.component.ts +491 -475
- package/src/lib/components/select/select-multi-dropdown/multi-dropdown-select.types.ts +22 -0
- package/src/lib/components/select/select-multi-dropdown/multi-dropdown-select.util.ts +20 -0
- package/src/lib/components/select/select-multi-table/multi-table-select.component.css +10 -0
- package/src/lib/components/select/select-multi-table/multi-table-select.component.html +76 -60
- package/src/lib/components/select/select-multi-table/multi-table-select.component.ts +250 -313
- package/src/lib/components/select/select-multi-table/multi-table-select.types.ts +10 -0
- package/src/lib/components/select/select-multi-table/multi-table-select.util.ts +5 -0
- package/src/lib/components/sidebar/sidebar-static/static-sidebar.component.css +212 -0
- package/src/lib/components/sidebar/sidebar-static/static-sidebar.component.html +62 -53
- package/src/lib/components/sidebar/sidebar-static/static-sidebar.component.ts +84 -27
- package/src/lib/components/sidebar/sidebar-static/static-sidebar.types.ts +2 -0
- package/src/lib/components/table/table-complete/complete-table.component.html +15 -17
- package/src/lib/components/table/table-complete/complete-table.component.ts +190 -338
- package/src/lib/components/table/table-complete/complete-table.types.ts +28 -0
- package/src/lib/components/table/table-complete/complete-table.util.ts +236 -0
- package/src/lib/components/table/table-complete/index.ts +2 -0
- package/src/lib/components/table/table-crud-complete/complete-crud-table.animations.ts +34 -0
- package/src/lib/components/table/table-crud-complete/complete-crud-table.component.html +73 -128
- package/src/lib/components/table/table-crud-complete/complete-crud-table.component.ts +542 -829
- package/src/lib/components/table/table-crud-complete/complete-crud-table.types.ts +57 -0
- package/src/lib/components/table/table-crud-complete/complete-crud-table.util.ts +723 -0
- package/src/lib/components/table/table-crud-complete/index.ts +3 -0
- package/src/lib/components/theme-generator/theme-generator.component.css +21 -0
- package/src/lib/components/theme-generator/theme-generator.component.html +146 -116
- package/src/lib/components/theme-generator/theme-generator.component.ts +44 -24
- package/src/lib/components/toggle-radio/shared/toggle-options.types.ts +8 -0
- package/src/lib/components/toggle-radio/shared/toggle-options.util.ts +44 -0
- package/src/lib/components/toggle-radio/toggle-radio/toggle-radio.component.css +135 -0
- package/src/lib/components/toggle-radio/toggle-radio/toggle-radio.component.html +52 -0
- package/src/lib/components/toggle-radio/toggle-radio/toggle-radio.component.ts +198 -0
- package/src/lib/components/toggle-radio/toggle-radio/toggle-radio.types.ts +1 -0
- package/src/lib/components/toggle-radio/toggle-segment/segment-toggle.component.css +108 -0
- package/src/lib/components/toggle-radio/toggle-segment/segment-toggle.component.html +37 -0
- package/src/lib/components/toggle-radio/toggle-segment/segment-toggle.component.ts +193 -0
- package/src/lib/components/toggle-radio/toggle-segment/segment-toggle.types.ts +1 -0
- package/src/lib/components/tooltip/tooltip.directive.ts +12 -9
- package/src/lib/components/tooltip/tooltip.service.ts +331 -133
- package/src/lib/components/tooltip/tooltip.types.ts +9 -0
- package/src/lib/components/viewer/viewer-image/image-viewer.component.css +90 -4
- package/src/lib/components/viewer/viewer-image/image-viewer.component.html +52 -103
- package/src/lib/components/viewer/viewer-image/image-viewer.component.ts +182 -177
- package/src/lib/components/viewer/viewer-image/image-viewer.types.ts +3 -0
- package/src/lib/components/viewer/viewer-pdf/pdf-viewer.component.css +177 -0
- package/src/lib/components/viewer/viewer-pdf/pdf-viewer.component.html +74 -24
- package/src/lib/components/viewer/viewer-pdf/pdf-viewer.component.ts +168 -15
- package/src/lib/components/viewer/viewer-pdf/pdf-viewer.types.ts +1 -0
- package/src/styles.css +2 -2
- package/lib/services/static/icons.service.d.ts +0 -65
- package/src/lib/components/colors-config/README.md +0 -38
- package/src/lib/components/form/form-sidebar/sidebar-form.component.scss +0 -0
- package/src/lib/components/form/form-validation/validation-form.component.scss +0 -0
- package/src/lib/components/menu/menu-options-table/options-table-menu.component.scss +0 -0
- package/src/lib/components/menu/options-coach-menu/options-coach-menu.component.scss +0 -12
- package/src/lib/components/sidebar/sidebar-static/static-sidebar.component.scss +0 -0
- package/src/lib/components/toggle-radio/toggle-radio.component.html +0 -51
- package/src/lib/components/toggle-radio/toggle-radio.component.ts +0 -222
- package/src/lib/components/viewer/viewer-pdf/pdf-viewer.component.scss +0 -0
- 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,153 @@
|
|
|
1
1
|
<main class="container mx-auto">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
13
|
+
class="absolute inset-0 bg-gradient-to-br from-white to-transparent"
|
|
14
|
+
style="z-index: 1"
|
|
15
|
+
></div>
|
|
16
|
+
<div
|
|
17
|
+
class="absolute inset-0 bg-gradient-to-b from-transparent to-black"
|
|
18
|
+
style="z-index: 2"
|
|
19
|
+
></div>
|
|
20
|
+
<div
|
|
21
|
+
class="absolute inset-0"
|
|
22
|
+
[style.background]="
|
|
23
|
+
'linear-gradient(to right, hsl(' +
|
|
24
|
+
huePosition +
|
|
25
|
+
', 0%, 50%), hsl(' +
|
|
26
|
+
huePosition +
|
|
27
|
+
', 100%, 50%))'
|
|
28
|
+
"
|
|
29
|
+
style="z-index: 0"
|
|
30
|
+
></div>
|
|
31
|
+
<div
|
|
32
|
+
class="absolute w-6 h-6 rounded-full border-2 border-white transform -translate-x-1/2 -translate-y-1/2 cursor-pointer"
|
|
33
|
+
[style.left.%]="colorPickerPosition.x"
|
|
34
|
+
[style.top.%]="colorPickerPosition.y"
|
|
35
|
+
style="z-index: 3"
|
|
36
|
+
></div>
|
|
37
|
+
<div
|
|
38
|
+
class="absolute inset-0 cursor-pointer"
|
|
39
|
+
(mousedown)="startColorPicking($event)"
|
|
40
|
+
(mousemove)="updateColorPicking($event)"
|
|
41
|
+
(mouseup)="stopColorPicking()"
|
|
42
|
+
(mouseleave)="stopColorPicking()"
|
|
43
|
+
style="z-index: 4"
|
|
44
|
+
></div>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<!-- Color Spectrum -->
|
|
48
|
+
<div class="space-y-4">
|
|
49
|
+
<div class="relative">
|
|
50
|
+
<!-- Picker bar -->
|
|
51
|
+
<div
|
|
52
|
+
class="h-8 w-full rounded-lg overflow-hidden border border-border dark:border-dark-border relative"
|
|
53
|
+
>
|
|
54
|
+
<div
|
|
55
|
+
class="absolute inset-0"
|
|
56
|
+
[style.background]="hueGradient"
|
|
57
|
+
></div>
|
|
58
|
+
|
|
59
|
+
<input
|
|
60
|
+
type="range"
|
|
61
|
+
min="0"
|
|
62
|
+
max="360"
|
|
63
|
+
[value]="huePosition"
|
|
64
|
+
(input)="updateHueFromInput($event)"
|
|
65
|
+
class="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
|
|
118
66
|
/>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<!-- Ball outside the flow to stand out -->
|
|
70
|
+
<div
|
|
71
|
+
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"
|
|
72
|
+
[style.left.%]="(huePosition / 360) * 100"
|
|
73
|
+
[style.backgroundColor]="hslToHex(huePosition, 100, 50)"
|
|
74
|
+
></div>
|
|
119
75
|
</div>
|
|
76
|
+
|
|
77
|
+
<!-- Hex Input -->
|
|
78
|
+
<JFormContainer>
|
|
79
|
+
<JFormContainer>
|
|
80
|
+
<JLabel for="baseColor" classes="opacity-60"
|
|
81
|
+
>Ingresa un valor Hex</JLabel
|
|
82
|
+
>
|
|
83
|
+
|
|
84
|
+
<JFormContainer [rows]="true" [gap]="3">
|
|
85
|
+
<JFormContainer class="flex-1">
|
|
86
|
+
<JInput
|
|
87
|
+
id="baseColor"
|
|
88
|
+
type="text"
|
|
89
|
+
[(ngModel)]="baseColor"
|
|
90
|
+
(input)="updateFromHexInput()"
|
|
91
|
+
placeholder="#000000"
|
|
92
|
+
/>
|
|
93
|
+
</JFormContainer>
|
|
94
|
+
|
|
95
|
+
<!-- Color Preview -->
|
|
96
|
+
<div
|
|
97
|
+
class="h-[35px] w-[60px] rounded shadow-md"
|
|
98
|
+
[style.background-color]="baseColor"
|
|
99
|
+
></div>
|
|
100
|
+
</JFormContainer>
|
|
101
|
+
</JFormContainer>
|
|
102
|
+
|
|
103
|
+
<!-- Saturation Slider -->
|
|
104
|
+
<JRangeInput
|
|
105
|
+
[min]="0"
|
|
106
|
+
[max]="100"
|
|
107
|
+
[(ngModel)]="saturation"
|
|
108
|
+
(input)="generateTheme()"
|
|
109
|
+
placeholder="Saturación"
|
|
110
|
+
[isLabel]="true"
|
|
111
|
+
simbol="%"
|
|
112
|
+
/>
|
|
113
|
+
|
|
114
|
+
<!-- Lightness Slider -->
|
|
115
|
+
<JRangeInput
|
|
116
|
+
[min]="0"
|
|
117
|
+
[max]="100"
|
|
118
|
+
[(ngModel)]="lightness"
|
|
119
|
+
(input)="generateTheme()"
|
|
120
|
+
placeholder="Luminosidad"
|
|
121
|
+
[isLabel]="true"
|
|
122
|
+
simbol="%"
|
|
123
|
+
/>
|
|
124
|
+
</JFormContainer>
|
|
125
|
+
</div>
|
|
120
126
|
</div>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
121
129
|
|
|
130
|
+
<!-- Code Preview -->
|
|
131
|
+
<div class="relative">
|
|
132
|
+
<div
|
|
133
|
+
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"
|
|
134
|
+
>
|
|
135
|
+
<div class="p-4">
|
|
136
|
+
<span>{{ themeCode }}</span>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<div class="absolute top-4 right-4 flex gap-1">
|
|
141
|
+
<JButton
|
|
142
|
+
(clicked)="copyThemeToClipboard()"
|
|
143
|
+
[icon]="Icons.Copy"
|
|
144
|
+
[iconChange]="Icons.Check"
|
|
145
|
+
[isChangeIcon]="copied"
|
|
146
|
+
[iconSize]="15"
|
|
147
|
+
tooltip="Copiar"
|
|
148
|
+
classes="w-[25px] h-[25px]"
|
|
149
|
+
/>
|
|
150
|
+
</div>
|
|
122
151
|
</div>
|
|
123
|
-
</
|
|
152
|
+
</div>
|
|
153
|
+
</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,
|
|
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: [
|
|
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
|
-
|
|
56
|
-
this.
|
|
61
|
+
ngOnDestroy(): void {
|
|
62
|
+
if (typeof this.themeService.clearPreviewColors === 'function') {
|
|
63
|
+
this.themeService.clearPreviewColors();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
57
66
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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,44 @@
|
|
|
1
|
+
import { ToggleOption } from './toggle-options.types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Reads a nested property using dot notation.
|
|
5
|
+
*/
|
|
6
|
+
export function getNestedToggleValue(obj: unknown, path: string): string {
|
|
7
|
+
if (!obj || typeof obj !== 'object') {
|
|
8
|
+
return '';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const value = path.split('.').reduce<unknown>((acc, part) => {
|
|
12
|
+
if (acc && typeof acc === 'object' && part in (acc as Record<string, unknown>)) {
|
|
13
|
+
return (acc as Record<string, unknown>)[part];
|
|
14
|
+
}
|
|
15
|
+
return undefined;
|
|
16
|
+
}, obj);
|
|
17
|
+
|
|
18
|
+
return value == null ? '' : String(value);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Normalizes static options into `{ value, label }` pairs.
|
|
23
|
+
*/
|
|
24
|
+
export function normalizeToggleOptions(
|
|
25
|
+
options: unknown[],
|
|
26
|
+
optionLabel: string,
|
|
27
|
+
optionValue: string,
|
|
28
|
+
): ToggleOption[] {
|
|
29
|
+
if (!options.length) {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (typeof options[0] === 'object' && options[0] !== null) {
|
|
34
|
+
return options.map((opt) => ({
|
|
35
|
+
value: (opt as Record<string, unknown>)[optionValue],
|
|
36
|
+
label: getNestedToggleValue(opt, optionLabel),
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return options.map((opt) => ({
|
|
41
|
+
value: opt,
|
|
42
|
+
label: String(opt),
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
display: block;
|
|
3
|
+
width: 100%;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.j-radio-group {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
gap: 0.625rem;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.j-radio-group--horizontal {
|
|
13
|
+
flex-flow: row wrap;
|
|
14
|
+
gap: 1rem 1.25rem;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.j-radio-group--disabled {
|
|
18
|
+
opacity: 0.55;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.j-radio-option {
|
|
22
|
+
display: inline-flex;
|
|
23
|
+
align-items: center;
|
|
24
|
+
gap: 0.625rem;
|
|
25
|
+
cursor: pointer;
|
|
26
|
+
user-select: none;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.j-radio-option--disabled {
|
|
30
|
+
cursor: not-allowed;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.j-radio-input {
|
|
34
|
+
position: absolute;
|
|
35
|
+
opacity: 0;
|
|
36
|
+
width: 0;
|
|
37
|
+
height: 0;
|
|
38
|
+
margin: 0;
|
|
39
|
+
pointer-events: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.j-radio-input:focus-visible + .j-radio-indicator {
|
|
43
|
+
outline: 2px solid var(--color-ring);
|
|
44
|
+
outline-offset: 2px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.j-radio-indicator {
|
|
48
|
+
display: inline-flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
justify-content: center;
|
|
51
|
+
width: 1.125rem;
|
|
52
|
+
height: 1.125rem;
|
|
53
|
+
flex-shrink: 0;
|
|
54
|
+
border: 1.5px solid var(--color-border);
|
|
55
|
+
border-radius: 9999px;
|
|
56
|
+
background-color: var(--color-background);
|
|
57
|
+
transition:
|
|
58
|
+
border-color 0.15s ease,
|
|
59
|
+
background-color 0.15s ease;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
:host-context(.dark) .j-radio-indicator,
|
|
63
|
+
:host-context(html.dark) .j-radio-indicator {
|
|
64
|
+
border-color: var(--color-dark-border);
|
|
65
|
+
background-color: var(--color-dark-background);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.j-radio-dot {
|
|
69
|
+
width: 0.4375rem;
|
|
70
|
+
height: 0.4375rem;
|
|
71
|
+
border-radius: 9999px;
|
|
72
|
+
background-color: var(--color-primary);
|
|
73
|
+
transform: scale(0);
|
|
74
|
+
transition: transform 0.15s ease;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
:host-context(.dark) .j-radio-dot,
|
|
78
|
+
:host-context(html.dark) .j-radio-dot {
|
|
79
|
+
background-color: var(--color-dark-primary);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.j-radio-option--selected .j-radio-indicator {
|
|
83
|
+
border-color: var(--color-primary);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
:host-context(.dark) .j-radio-option--selected .j-radio-indicator,
|
|
87
|
+
:host-context(html.dark) .j-radio-option--selected .j-radio-indicator {
|
|
88
|
+
border-color: var(--color-dark-primary);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.j-radio-option--selected .j-radio-dot {
|
|
92
|
+
transform: scale(1);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.j-radio-label {
|
|
96
|
+
font-size: 0.875rem;
|
|
97
|
+
line-height: 1.35;
|
|
98
|
+
color: var(--color-foreground);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
:host-context(.dark) .j-radio-label,
|
|
102
|
+
:host-context(html.dark) .j-radio-label {
|
|
103
|
+
color: var(--color-dark-foreground);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.j-radio-state {
|
|
107
|
+
display: flex;
|
|
108
|
+
align-items: center;
|
|
109
|
+
justify-content: flex-start;
|
|
110
|
+
gap: 0.5rem;
|
|
111
|
+
min-height: 2rem;
|
|
112
|
+
color: var(--color-muted-foreground);
|
|
113
|
+
font-size: 0.875rem;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
:host-context(.dark) .j-radio-state,
|
|
117
|
+
:host-context(html.dark) .j-radio-state {
|
|
118
|
+
color: var(--color-dark-muted-foreground);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.j-radio-clear {
|
|
122
|
+
margin-top: 0.625rem;
|
|
123
|
+
padding: 0;
|
|
124
|
+
border: 0;
|
|
125
|
+
background: transparent;
|
|
126
|
+
color: var(--color-destructive);
|
|
127
|
+
font-size: 0.75rem;
|
|
128
|
+
text-decoration: underline;
|
|
129
|
+
cursor: pointer;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.j-radio-clear:disabled {
|
|
133
|
+
opacity: 0.5;
|
|
134
|
+
cursor: not-allowed;
|
|
135
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
@if (internalOptions.length > 0) {
|
|
2
|
+
<div [ngClass]="groupClasses" role="radiogroup">
|
|
3
|
+
@for (opt of internalOptions; track $index) {
|
|
4
|
+
<label
|
|
5
|
+
class="j-radio-option"
|
|
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"
|
|
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 class="j-radio-indicator" aria-hidden="true">
|
|
22
|
+
<span class="j-radio-dot"></span>
|
|
23
|
+
</span>
|
|
24
|
+
|
|
25
|
+
<span class="j-radio-label">{{ opt.label }}</span>
|
|
26
|
+
</label>
|
|
27
|
+
}
|
|
28
|
+
</div>
|
|
29
|
+
} @else if (isLoading) {
|
|
30
|
+
<div class="j-radio-state">
|
|
31
|
+
<JIcon
|
|
32
|
+
[icon]="Icons.Loader2"
|
|
33
|
+
[size]="16"
|
|
34
|
+
iconClass="animate-spin text-muted-foreground"
|
|
35
|
+
[ariaHidden]="true"
|
|
36
|
+
/>
|
|
37
|
+
<span>Cargando...</span>
|
|
38
|
+
</div>
|
|
39
|
+
} @else {
|
|
40
|
+
<div class="j-radio-state">No hay opciones</div>
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@if (showClear && selectedValue !== null) {
|
|
44
|
+
<button
|
|
45
|
+
type="button"
|
|
46
|
+
class="j-radio-clear"
|
|
47
|
+
(click)="clear()"
|
|
48
|
+
[disabled]="isInteractionDisabled"
|
|
49
|
+
>
|
|
50
|
+
Limpiar selección
|
|
51
|
+
</button>
|
|
52
|
+
}
|