@axzydev/axzy_ui_system 1.2.1 → 1.2.3

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 (207) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.css +82 -1
  4. package/dist/index.css.map +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/index.js.map +1 -1
  7. package/package.json +2 -2
  8. package/src/App.tsx +354 -0
  9. package/src/assets/logo.png +0 -0
  10. package/src/assets/react.svg +1 -0
  11. package/src/components/alert/alert.props.ts +13 -0
  12. package/src/components/alert/alert.stories.tsx +41 -0
  13. package/src/components/alert/alert.tsx +53 -0
  14. package/src/components/avatar/avatar.props.ts +14 -0
  15. package/src/components/avatar/avatar.stories.tsx +46 -0
  16. package/src/components/avatar/avatar.tsx +53 -0
  17. package/src/components/badget/badget.props.ts +12 -0
  18. package/src/components/badget/badget.stories.tsx +76 -0
  19. package/src/components/badget/badget.tsx +61 -0
  20. package/src/components/breadcrumbs/breadcrumbs.props.ts +13 -0
  21. package/src/components/breadcrumbs/breadcrumbs.stories.tsx +21 -0
  22. package/src/components/breadcrumbs/breadcrumbs.tsx +34 -0
  23. package/src/components/button/button.props.ts +18 -0
  24. package/src/components/button/button.stories.tsx +174 -0
  25. package/src/components/button/button.tsx +117 -0
  26. package/src/components/calendar/calendar.props.ts +33 -0
  27. package/src/components/calendar/calendar.stories.tsx +91 -0
  28. package/src/components/calendar/calendar.tsx +608 -0
  29. package/src/components/calendar/index.ts +3 -0
  30. package/src/components/card/card.props.ts +13 -0
  31. package/src/components/card/card.stories.tsx +58 -0
  32. package/src/components/card/card.tsx +79 -0
  33. package/src/components/checkbox/checkbox.props.ts +11 -0
  34. package/src/components/checkbox/checkbox.stories.tsx +54 -0
  35. package/src/components/checkbox/checkbox.tsx +52 -0
  36. package/src/components/confirm-dialog/confirm-dialog.props.ts +14 -0
  37. package/src/components/confirm-dialog/confirm-dialog.stories.tsx +33 -0
  38. package/src/components/confirm-dialog/confirm-dialog.tsx +45 -0
  39. package/src/components/data-table/ITDataTable.stories.tsx +213 -0
  40. package/src/components/data-table/dataTable.props.ts +69 -0
  41. package/src/components/data-table/dataTable.tsx +313 -0
  42. package/src/components/date-picker/date-picker.props.ts +30 -0
  43. package/src/components/date-picker/date-picker.stories.tsx +90 -0
  44. package/src/components/date-picker/datePicker.tsx +307 -0
  45. package/src/components/dialog/dialog.props.ts +9 -0
  46. package/src/components/dialog/dialog.stories.tsx +80 -0
  47. package/src/components/dialog/dialog.tsx +88 -0
  48. package/src/components/divider/divider.props.ts +8 -0
  49. package/src/components/divider/divider.stories.tsx +34 -0
  50. package/src/components/divider/divider.tsx +21 -0
  51. package/src/components/drawer/drawer.props.ts +14 -0
  52. package/src/components/drawer/drawer.stories.tsx +41 -0
  53. package/src/components/drawer/drawer.tsx +53 -0
  54. package/src/components/dropfile/dropfile.stories.tsx +75 -0
  55. package/src/components/dropfile/dropfile.tsx +407 -0
  56. package/src/components/empty-state/empty-state.props.ts +9 -0
  57. package/src/components/empty-state/empty-state.stories.tsx +20 -0
  58. package/src/components/empty-state/empty-state.tsx +21 -0
  59. package/src/components/flex/flex.props.ts +22 -0
  60. package/src/components/flex/flex.stories.tsx +71 -0
  61. package/src/components/flex/flex.tsx +79 -0
  62. package/src/components/form-builder/fieldRenderer.tsx +218 -0
  63. package/src/components/form-builder/formBuilder.context.tsx +70 -0
  64. package/src/components/form-builder/formBuilder.props.ts +43 -0
  65. package/src/components/form-builder/formBuilder.stories.tsx +317 -0
  66. package/src/components/form-builder/formBuilder.tsx +186 -0
  67. package/src/components/form-builder/useFormBuilder.ts +80 -0
  68. package/src/components/form-header/form-header.props.ts +5 -0
  69. package/src/components/form-header/form-header.tsx +38 -0
  70. package/src/components/grid/grid.props.ts +17 -0
  71. package/src/components/grid/grid.stories.tsx +72 -0
  72. package/src/components/grid/grid.tsx +69 -0
  73. package/src/components/image/image.props.ts +7 -0
  74. package/src/components/image/image.tsx +38 -0
  75. package/src/components/input/input.props.ts +49 -0
  76. package/src/components/input/input.stories.tsx +115 -0
  77. package/src/components/input/input.tsx +615 -0
  78. package/src/components/layout/layout.props.ts +10 -0
  79. package/src/components/layout/layout.stories.tsx +114 -0
  80. package/src/components/layout/layout.tsx +80 -0
  81. package/src/components/loader/loader.props.ts +8 -0
  82. package/src/components/loader/loader.stories.tsx +105 -0
  83. package/src/components/loader/loader.tsx +108 -0
  84. package/src/components/navbar/navbar.props.ts +37 -0
  85. package/src/components/navbar/navbar.tsx +328 -0
  86. package/src/components/page/page.props.ts +19 -0
  87. package/src/components/page/page.stories.tsx +98 -0
  88. package/src/components/page/page.tsx +90 -0
  89. package/src/components/page-header/page-header.props.ts +11 -0
  90. package/src/components/page-header/page-header.stories.tsx +61 -0
  91. package/src/components/page-header/page-header.tsx +62 -0
  92. package/src/components/pagination/pagination.props.ts +53 -0
  93. package/src/components/pagination/pagination.stories.tsx +111 -0
  94. package/src/components/pagination/pagination.tsx +241 -0
  95. package/src/components/popover/popover.props.ts +12 -0
  96. package/src/components/popover/popover.stories.tsx +25 -0
  97. package/src/components/popover/popover.tsx +45 -0
  98. package/src/components/progress/progress.props.ts +12 -0
  99. package/src/components/progress/progress.stories.tsx +40 -0
  100. package/src/components/progress/progress.tsx +52 -0
  101. package/src/components/radio/radio.props.ts +16 -0
  102. package/src/components/radio/radio.stories.tsx +50 -0
  103. package/src/components/radio/radio.tsx +58 -0
  104. package/src/components/search-select/index.ts +2 -0
  105. package/src/components/search-select/search-select.props.ts +46 -0
  106. package/src/components/search-select/search-select.stories.tsx +129 -0
  107. package/src/components/search-select/search-select.tsx +229 -0
  108. package/src/components/searchTable/components/EditableCell.tsx +149 -0
  109. package/src/components/searchTable/components/PaginationControls.tsx +86 -0
  110. package/src/components/searchTable/components/PaginationInfo.tsx +20 -0
  111. package/src/components/searchTable/components/SearchAndSortBar.tsx +53 -0
  112. package/src/components/searchTable/components/SearchInput.tsx +33 -0
  113. package/src/components/searchTable/components/SortButton.tsx +50 -0
  114. package/src/components/searchTable/components/TableEmptyState.tsx +22 -0
  115. package/src/components/searchTable/components/TableHeader.tsx +35 -0
  116. package/src/components/searchTable/components/TableHeaderCell.tsx +43 -0
  117. package/src/components/searchTable/components/TableRow.tsx +144 -0
  118. package/src/components/searchTable/searchTable.props.ts +56 -0
  119. package/src/components/searchTable/searchTable.tsx +187 -0
  120. package/src/components/segmented-control/segmented-control.props.ts +18 -0
  121. package/src/components/segmented-control/segmented-control.stories.tsx +63 -0
  122. package/src/components/segmented-control/segmented-control.tsx +52 -0
  123. package/src/components/select/select.props.ts +25 -0
  124. package/src/components/select/select.stories.tsx +86 -0
  125. package/src/components/select/select.tsx +150 -0
  126. package/src/components/sidebar/sidebar.props.ts +28 -0
  127. package/src/components/sidebar/sidebar.stories.tsx +117 -0
  128. package/src/components/sidebar/sidebar.tsx +313 -0
  129. package/src/components/skeleton/skeleton.props.ts +12 -0
  130. package/src/components/skeleton/skeleton.stories.tsx +30 -0
  131. package/src/components/skeleton/skeleton.tsx +45 -0
  132. package/src/components/slide/slide.props.ts +45 -0
  133. package/src/components/slide/slide.stories.tsx +121 -0
  134. package/src/components/slide/slide.tsx +109 -0
  135. package/src/components/slider/slider.props.ts +10 -0
  136. package/src/components/slider/slider.stories.tsx +30 -0
  137. package/src/components/slider/slider.tsx +49 -0
  138. package/src/components/stack/stack.props.ts +19 -0
  139. package/src/components/stack/stack.stories.tsx +79 -0
  140. package/src/components/stack/stack.tsx +79 -0
  141. package/src/components/stat-card/stat-card.props.ts +13 -0
  142. package/src/components/stat-card/stat-card.stories.tsx +41 -0
  143. package/src/components/stat-card/stat-card.tsx +44 -0
  144. package/src/components/stepper/stepper.css +26 -0
  145. package/src/components/stepper/stepper.props.ts +29 -0
  146. package/src/components/stepper/stepper.stories.tsx +155 -0
  147. package/src/components/stepper/stepper.tsx +227 -0
  148. package/src/components/table/table.props.ts +43 -0
  149. package/src/components/table/table.stories.tsx +189 -0
  150. package/src/components/table/table.tsx +376 -0
  151. package/src/components/tabs/tabs.props.ts +18 -0
  152. package/src/components/tabs/tabs.stories.tsx +32 -0
  153. package/src/components/tabs/tabs.tsx +74 -0
  154. package/src/components/text/text.props.ts +9 -0
  155. package/src/components/text/text.tsx +20 -0
  156. package/src/components/textarea/textarea.props.ts +15 -0
  157. package/src/components/textarea/textarea.stories.tsx +27 -0
  158. package/src/components/textarea/textarea.tsx +55 -0
  159. package/src/components/theme-provider/themeProvider.props.ts +28 -0
  160. package/src/components/theme-provider/themeProvider.tsx +1854 -0
  161. package/src/components/time-picker/timePicker.props.ts +16 -0
  162. package/src/components/time-picker/timePicker.stories.tsx +131 -0
  163. package/src/components/time-picker/timePicker.tsx +317 -0
  164. package/src/components/toast/toast.css +32 -0
  165. package/src/components/toast/toast.props.ts +13 -0
  166. package/src/components/toast/toast.stories.tsx +138 -0
  167. package/src/components/toast/toast.tsx +87 -0
  168. package/src/components/tooltip/tooltip.props.ts +11 -0
  169. package/src/components/tooltip/tooltip.stories.tsx +20 -0
  170. package/src/components/tooltip/tooltip.tsx +55 -0
  171. package/src/components/topbar/topbar.props.ts +21 -0
  172. package/src/components/topbar/topbar.stories.tsx +80 -0
  173. package/src/components/topbar/topbar.tsx +205 -0
  174. package/src/components/triple-filter/tripleFilter.props.ts +15 -0
  175. package/src/components/triple-filter/tripleFilter.stories.tsx +32 -0
  176. package/src/components/triple-filter/tripleFilter.tsx +50 -0
  177. package/src/dev.css +2 -0
  178. package/src/hooks/useClickOutside.ts +21 -0
  179. package/src/hooks/useDebouncedSearch.ts +55 -0
  180. package/src/hooks/useEditableRow.ts +157 -0
  181. package/src/hooks/useTableState.ts +122 -0
  182. package/src/index.css +168 -0
  183. package/src/index.ts +165 -0
  184. package/src/main.tsx +9 -0
  185. package/src/showcases/DataShowcases.tsx +260 -0
  186. package/src/showcases/FeedbackShowcases.tsx +268 -0
  187. package/src/showcases/FormShowcases.tsx +1159 -0
  188. package/src/showcases/HomeShowcase.tsx +324 -0
  189. package/src/showcases/LayoutPrimitivesShowcases.tsx +569 -0
  190. package/src/showcases/NavigationShowcases.tsx +193 -0
  191. package/src/showcases/PageShowcases.tsx +207 -0
  192. package/src/showcases/ShowcaseLayout.tsx +139 -0
  193. package/src/showcases/StructureShowcases.tsx +152 -0
  194. package/src/types/badget.types.ts +37 -0
  195. package/src/types/button.types.ts +16 -0
  196. package/src/types/colors.types.ts +3 -0
  197. package/src/types/field.types.ts +103 -0
  198. package/src/types/formik.types.ts +15 -0
  199. package/src/types/input.types.ts +14 -0
  200. package/src/types/loader.types.ts +9 -0
  201. package/src/types/sizes.types.ts +1 -0
  202. package/src/types/table.types.ts +15 -0
  203. package/src/types/toast.types.ts +8 -0
  204. package/src/types/yup.types.ts +11 -0
  205. package/src/utils/color.utils.ts +99 -0
  206. package/src/utils/styles.ts +120 -0
  207. package/src/utils/table.utils.ts +10 -0
@@ -0,0 +1,1854 @@
1
+ import React, { createContext, useContext, useState, useEffect } from "react";
2
+ import { MdPalette, MdClose, MdRefresh } from "react-icons/md";
3
+ import { ITThemeProviderProps, ITThemePalette } from "./themeProvider.props";
4
+ import ITDialog from "../dialog/dialog";
5
+ import ITTabs from "../tabs/tabs";
6
+ import ITButton from "../button/button";
7
+ import ITInput from "../input/input";
8
+ import ITSegmentedControl from "../segmented-control/segmented-control";
9
+ import ITDivider from "../divider/divider";
10
+ import ITText from "@/components/text/text";
11
+
12
+ // ============================================================================
13
+ // DEFAULT PALETTE & PRESETS CONFIG
14
+ // ============================================================================
15
+
16
+ const STORAGE_KEY = "it-theme-palette";
17
+
18
+ export const DEFAULT_PALETTE: ITThemePalette = {
19
+ primary: "#06b6d4", // Cyan
20
+ secondary: "#6b7280", // Gray
21
+ ternary: "#8b5cf6", // Purple/Violet
22
+ danger: "#ef4444", // Red
23
+ success: "#22c55e", // Green
24
+ info: "#3b82f6", // Blue
25
+ alert: "#f97316", // Orange
26
+ warning: "#eab308", // Yellow
27
+ layout: {
28
+ sidebarBg: "#ffffff", // White (light mode default)
29
+ sidebarText: "#334155", // Slate-700 (dark text for light sidebar)
30
+ navbarBg: "#ffffff", // White
31
+ navbarText: "#1e293b", // Slate-800
32
+ },
33
+ table: {
34
+ headerBg: "#f8fafc", // Slate-50
35
+ headerText: "#334155", // Slate-700
36
+ rowBg: "#ffffff", // White
37
+ rowText: "#1e293b", // Slate-800
38
+ },
39
+ };
40
+
41
+ export const PRESETS: { name: string; colors: ITThemePalette }[] = [
42
+ {
43
+ name: "Midnight Indigo 🌌",
44
+ colors: {
45
+ primary: "#6366f1",
46
+ secondary: "#475569",
47
+ ternary: "#f472b6",
48
+ danger: "#ef4444",
49
+ success: "#34d399",
50
+ info: "#06b6d4",
51
+ alert: "#fb923c",
52
+ warning: "#fbbf24",
53
+ layout: {
54
+ sidebarBg: "#0b1120",
55
+ sidebarText: "#94a3b8",
56
+ navbarBg: "#0f172a",
57
+ navbarText: "#f1f5f9",
58
+ },
59
+ table: {
60
+ headerBg: "#f1f5f9",
61
+ headerText: "#334155",
62
+ rowBg: "#ffffff",
63
+ rowText: "#0f172a",
64
+ },
65
+ },
66
+ },
67
+ {
68
+ name: "Coral Reef 🪸",
69
+ colors: {
70
+ primary: "#f43f5e",
71
+ secondary: "#57534e",
72
+ ternary: "#f97316",
73
+ danger: "#b91c1c",
74
+ success: "#14b8a6",
75
+ info: "#6366f1",
76
+ alert: "#eab308",
77
+ warning: "#fde047",
78
+ layout: {
79
+ sidebarBg: "#0c0808",
80
+ sidebarText: "#fda4af",
81
+ navbarBg: "#1c1212",
82
+ navbarText: "#fff1f2",
83
+ },
84
+ table: {
85
+ headerBg: "#fff1f2",
86
+ headerText: "#881337",
87
+ rowBg: "#ffffff",
88
+ rowText: "#1c1212",
89
+ },
90
+ },
91
+ },
92
+ {
93
+ name: "Oceanic Teal 🌊",
94
+ colors: {
95
+ primary: "#0d9488",
96
+ secondary: "#64748b",
97
+ ternary: "#a78bfa",
98
+ danger: "#e11d48",
99
+ success: "#22c55e",
100
+ info: "#0284c7",
101
+ alert: "#ea580c",
102
+ warning: "#ca8a04",
103
+ layout: {
104
+ sidebarBg: "#042f2e",
105
+ sidebarText: "#5eead4",
106
+ navbarBg: "#062b2a",
107
+ navbarText: "#ccfbf1",
108
+ },
109
+ table: {
110
+ headerBg: "#f0fdfa",
111
+ headerText: "#115e59",
112
+ rowBg: "#ffffff",
113
+ rowText: "#042f2e",
114
+ },
115
+ },
116
+ },
117
+ {
118
+ name: "Golden Hour ☀️",
119
+ colors: {
120
+ primary: "#d97706",
121
+ secondary: "#78716c",
122
+ ternary: "#db2777",
123
+ danger: "#dc2626",
124
+ success: "#65a30d",
125
+ info: "#2563eb",
126
+ alert: "#f97316",
127
+ warning: "#facc15",
128
+ layout: {
129
+ sidebarBg: "#fefce8",
130
+ sidebarText: "#713f12",
131
+ navbarBg: "#fffbeb",
132
+ navbarText: "#451a03",
133
+ },
134
+ table: {
135
+ headerBg: "#fefce8",
136
+ headerText: "#713f12",
137
+ rowBg: "#ffffff",
138
+ rowText: "#292524",
139
+ },
140
+ },
141
+ },
142
+ {
143
+ name: "Deep Forest 🌲",
144
+ colors: {
145
+ primary: "#16a34a",
146
+ secondary: "#57534e",
147
+ ternary: "#d946ef",
148
+ danger: "#dc2626",
149
+ success: "#14b8a6",
150
+ info: "#0ea5e9",
151
+ alert: "#f97316",
152
+ warning: "#eab308",
153
+ layout: {
154
+ sidebarBg: "#052e16",
155
+ sidebarText: "#86efac",
156
+ navbarBg: "#0b3b1c",
157
+ navbarText: "#dcfce7",
158
+ },
159
+ table: {
160
+ headerBg: "#f0fdf4",
161
+ headerText: "#166534",
162
+ rowBg: "#ffffff",
163
+ rowText: "#052e16",
164
+ },
165
+ },
166
+ },
167
+ ];
168
+ // ============================================================================
169
+ // CONTEXT & PROVIDER
170
+ // ============================================================================
171
+
172
+ interface ITThemeContextType {
173
+ palette: ITThemePalette;
174
+ colors: ITThemePalette;
175
+ setPalette: (newPalette: ITThemePalette) => void;
176
+ updateColor: (key: string, value: string) => void;
177
+ resetTheme: () => void;
178
+ applyPreset: (colors: ITThemePalette) => void;
179
+ resolvedTheme: "light" | "dark";
180
+ darkModeMode: "light" | "dark" | "system";
181
+ setDarkModeMode: (mode: "light" | "dark" | "system") => void;
182
+ }
183
+
184
+ const ITThemeContext = createContext<ITThemeContextType | undefined>(undefined);
185
+
186
+ export const useITTheme = () => {
187
+ const context = useContext(ITThemeContext);
188
+ if (!context) {
189
+ throw new Error("useITTheme must be used within an ITThemeProvider");
190
+ }
191
+ return context;
192
+ };
193
+
194
+ /**
195
+ * Versión segura de useITTheme que retorna undefined
196
+ * si se usa fuera de ITThemeProvider (no lanza error).
197
+ */
198
+ export const useITThemeSafe = (): ITThemeContextType | undefined => {
199
+ return useContext(ITThemeContext);
200
+ };
201
+
202
+ const getNestedValue = (obj: any, path: string) => {
203
+ return path.split(".").reduce((acc, part) => acc && acc[part], obj);
204
+ };
205
+
206
+ const isLightColor = (hex: string) => {
207
+ if (!hex || typeof hex !== "string") return false;
208
+ const color = hex.replace("#", "");
209
+ let r = 0,
210
+ g = 0,
211
+ b = 0;
212
+ if (color.length === 3) {
213
+ r = parseInt(color[0] + color[0], 16);
214
+ g = parseInt(color[1] + color[1], 16);
215
+ b = parseInt(color[2] + color[2], 16);
216
+ } else if (color.length === 6) {
217
+ r = parseInt(color.substring(0, 2), 16);
218
+ g = parseInt(color.substring(2, 4), 16);
219
+ b = parseInt(color.substring(4, 6), 16);
220
+ } else {
221
+ return false;
222
+ }
223
+ const brightness = (r * 299 + g * 587 + b * 114) / 1000;
224
+ return brightness > 140;
225
+ };
226
+
227
+ /** Returns true if the hex color is very dark (brightness < 50) */
228
+ const isVeryDarkColor = (hex: string) => {
229
+ if (!hex || typeof hex !== "string") return false;
230
+ const color = hex.replace("#", "");
231
+ let r = 0,
232
+ g = 0,
233
+ b = 0;
234
+ if (color.length === 3) {
235
+ r = parseInt(color[0] + color[0], 16);
236
+ g = parseInt(color[1] + color[1], 16);
237
+ b = parseInt(color[2] + color[2], 16);
238
+ } else if (color.length === 6) {
239
+ r = parseInt(color.substring(0, 2), 16);
240
+ g = parseInt(color.substring(2, 4), 16);
241
+ b = parseInt(color.substring(4, 6), 16);
242
+ } else {
243
+ return false;
244
+ }
245
+ const brightness = (r * 299 + g * 587 + b * 114) / 1000;
246
+ return brightness < 50;
247
+ };
248
+
249
+ export default function ITThemeProvider({
250
+ children,
251
+ theme,
252
+ showFab = true,
253
+ }: ITThemeProviderProps) {
254
+ const [palette, setPaletteState] = useState<ITThemePalette>(() => {
255
+ const basePalette = {
256
+ ...DEFAULT_PALETTE,
257
+ ...theme,
258
+ layout: { ...DEFAULT_PALETTE.layout, ...theme?.layout },
259
+ table: { ...DEFAULT_PALETTE.table, ...theme?.table },
260
+ };
261
+ if (!showFab) {
262
+ return basePalette as ITThemePalette;
263
+ }
264
+ try {
265
+ const saved = localStorage.getItem(STORAGE_KEY);
266
+ if (saved) {
267
+ const parsed = JSON.parse(saved);
268
+ return {
269
+ ...basePalette,
270
+ ...parsed,
271
+ layout: { ...basePalette.layout, ...parsed.layout },
272
+ table: { ...basePalette.table, ...parsed.table },
273
+ };
274
+ }
275
+ } catch (e) {
276
+ console.error("Failed to load theme from localStorage", e);
277
+ }
278
+ return basePalette as ITThemePalette;
279
+ });
280
+
281
+ const [isOpen, setIsOpen] = useState(false);
282
+ const [customPresets, setCustomPresets] = useState<
283
+ { name: string; colors: ITThemePalette }[]
284
+ >(() => {
285
+ try {
286
+ const saved = localStorage.getItem("it-theme-custom-presets");
287
+ return saved ? JSON.parse(saved) : [];
288
+ } catch (e) {
289
+ console.error("Failed to load custom presets", e);
290
+ return [];
291
+ }
292
+ });
293
+ const [newPresetName, setNewPresetName] = useState("");
294
+ const [isSavingPreset, setIsSavingPreset] = useState(false);
295
+
296
+ const handleSavePreset = () => {
297
+ if (!newPresetName.trim()) return;
298
+ const newPreset = {
299
+ name: newPresetName.trim(),
300
+ colors: JSON.parse(JSON.stringify(palette)),
301
+ };
302
+ const updated = [...customPresets, newPreset];
303
+ setCustomPresets(updated);
304
+ localStorage.setItem("it-theme-custom-presets", JSON.stringify(updated));
305
+ setNewPresetName("");
306
+ setIsSavingPreset(false);
307
+ };
308
+
309
+ const handleDeletePreset = (nameToDelete: string, e: React.MouseEvent) => {
310
+ e.stopPropagation();
311
+ const updated = customPresets.filter((p) => p.name !== nameToDelete);
312
+ setCustomPresets(updated);
313
+ localStorage.setItem("it-theme-custom-presets", JSON.stringify(updated));
314
+ };
315
+
316
+ const [resolvedTheme, setResolvedTheme] = useState<"light" | "dark">("light");
317
+
318
+ const [darkModeMode, setDarkModeMode] = useState<"light" | "dark" | "system">(
319
+ () => {
320
+ const saved = localStorage.getItem("it-theme-dark-mode");
321
+ if (saved === "light" || saved === "dark" || saved === "system") {
322
+ return saved;
323
+ }
324
+ return "system";
325
+ },
326
+ );
327
+
328
+ useEffect(() => {
329
+ localStorage.setItem("it-theme-dark-mode", darkModeMode);
330
+
331
+ const applyDarkMode = (isDark: boolean) => {
332
+ if (isDark) {
333
+ document.documentElement.classList.add("dark");
334
+ document.documentElement.setAttribute("data-theme", "dark");
335
+ setResolvedTheme("dark");
336
+ } else {
337
+ document.documentElement.classList.remove("dark");
338
+ document.documentElement.setAttribute("data-theme", "light");
339
+ setResolvedTheme("light");
340
+ }
341
+ };
342
+
343
+ if (darkModeMode === "system") {
344
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
345
+ applyDarkMode(mediaQuery.matches);
346
+
347
+ const listener = (e: MediaQueryListEvent) => {
348
+ applyDarkMode(e.matches);
349
+ };
350
+
351
+ mediaQuery.addEventListener("change", listener);
352
+ return () => mediaQuery.removeEventListener("change", listener);
353
+ } else {
354
+ applyDarkMode(darkModeMode === "dark");
355
+ }
356
+ }, [darkModeMode]);
357
+
358
+ // Sync palette with theme prop when showFab is false
359
+ useEffect(() => {
360
+ if (!showFab) {
361
+ setPaletteState({
362
+ ...DEFAULT_PALETTE,
363
+ ...theme,
364
+ layout: { ...DEFAULT_PALETTE.layout, ...theme?.layout },
365
+ table: { ...DEFAULT_PALETTE.table, ...theme?.table },
366
+ });
367
+ }
368
+ }, [theme, showFab]);
369
+
370
+ // Inyectar variables CSS en el :root al cambiar la paleta o tema resuelto
371
+ useEffect(() => {
372
+ const injectStyles = (obj: any, prefix = "") => {
373
+ Object.entries(obj).forEach(([key, val]) => {
374
+ if (typeof val === "object" && val !== null) {
375
+ injectStyles(val, prefix + key + "-");
376
+ } else {
377
+ document.documentElement.style.setProperty(
378
+ `--color-${prefix}${key}`,
379
+ val as string,
380
+ );
381
+ if (prefix === "layout-") {
382
+ document.documentElement.style.setProperty(
383
+ `--color-${key}`,
384
+ val as string,
385
+ );
386
+ }
387
+ }
388
+ });
389
+ };
390
+ injectStyles(palette);
391
+ if (showFab) {
392
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(palette));
393
+ }
394
+
395
+ // Dynamic overrides for Tailwind classes and component tokens
396
+ let styleTag = document.getElementById(
397
+ "it-theme-dynamic-overrides",
398
+ ) as HTMLStyleElement;
399
+ if (!styleTag) {
400
+ styleTag = document.createElement("style");
401
+ styleTag.id = "it-theme-dynamic-overrides";
402
+ document.head.appendChild(styleTag);
403
+ }
404
+
405
+ const isDark = resolvedTheme === "dark";
406
+
407
+ let tableRowBg = palette.table.rowBg;
408
+ let tableRowText = palette.table.rowText;
409
+ let tableHeaderBg = palette.table.headerBg;
410
+ let tableHeaderText = palette.table.headerText;
411
+ let navbarBg = palette.layout.navbarBg;
412
+ let navbarText = palette.layout.navbarText;
413
+ let sidebarBg = palette.layout.sidebarBg;
414
+ let sidebarText = palette.layout.sidebarText;
415
+
416
+ if (isDark) {
417
+ if (isLightColor(tableRowBg)) {
418
+ tableRowBg = `color-mix(in srgb, ${palette.table.rowBg} 8%, #111827)`;
419
+ }
420
+ if (!isLightColor(tableRowText)) {
421
+ tableRowText = `color-mix(in srgb, ${palette.table.rowText} 20%, #f3f4f6)`;
422
+ }
423
+ if (isLightColor(tableHeaderBg)) {
424
+ tableHeaderBg = `color-mix(in srgb, ${palette.table.headerBg} 12%, #1f2937)`;
425
+ }
426
+ if (!isLightColor(tableHeaderText)) {
427
+ tableHeaderText = `color-mix(in srgb, ${palette.table.headerText} 20%, #f9fafb)`;
428
+ }
429
+ if (isLightColor(navbarBg)) {
430
+ navbarBg = `color-mix(in srgb, ${palette.layout.navbarBg} 8%, #111827)`;
431
+ }
432
+ if (!isLightColor(navbarText)) {
433
+ navbarText = `color-mix(in srgb, ${palette.layout.navbarText} 20%, #f3f4f6)`;
434
+ }
435
+ if (isLightColor(sidebarBg)) {
436
+ sidebarBg = `color-mix(in srgb, ${palette.layout.sidebarBg} 8%, #0f172a)`;
437
+ }
438
+ if (!isLightColor(sidebarText)) {
439
+ sidebarText = `color-mix(in srgb, ${palette.layout.sidebarText} 20%, #cbd5e1)`;
440
+ }
441
+ } else {
442
+ // Light mode: if table colors are dark (from a dark preset), override to clean light values
443
+ // Very dark colors (brightness < 50) get replaced directly to avoid dirty tints
444
+ if (!isLightColor(tableRowBg)) {
445
+ tableRowBg = isVeryDarkColor(palette.table.rowBg)
446
+ ? "#ffffff"
447
+ : `color-mix(in srgb, ${palette.table.rowBg} 8%, #ffffff)`;
448
+ }
449
+ if (isLightColor(tableRowText)) {
450
+ tableRowText = `color-mix(in srgb, ${palette.table.rowText} 30%, #1e293b)`;
451
+ } else if (
452
+ !isLightColor(tableRowText) &&
453
+ isVeryDarkColor(palette.table.rowText)
454
+ ) {
455
+ // Very dark text is fine for light mode, keep it
456
+ }
457
+ if (!isLightColor(tableHeaderBg)) {
458
+ tableHeaderBg = isVeryDarkColor(palette.table.headerBg)
459
+ ? "#f1f5f9"
460
+ : `color-mix(in srgb, ${palette.table.headerBg} 12%, #f8fafc)`;
461
+ }
462
+ if (isLightColor(tableHeaderText)) {
463
+ tableHeaderText = `color-mix(in srgb, ${palette.table.headerText} 30%, #334155)`;
464
+ } else if (
465
+ !isLightColor(tableHeaderText) &&
466
+ isVeryDarkColor(palette.table.headerText)
467
+ ) {
468
+ // Dark header text is fine for light mode
469
+ }
470
+ if (!isLightColor(navbarBg)) {
471
+ navbarBg = isVeryDarkColor(palette.layout.navbarBg)
472
+ ? "#ffffff"
473
+ : `color-mix(in srgb, ${palette.layout.navbarBg} 8%, #ffffff)`;
474
+ }
475
+ if (isLightColor(navbarText)) {
476
+ navbarText = `color-mix(in srgb, ${palette.layout.navbarText} 30%, #1e293b)`;
477
+ }
478
+ if (!isLightColor(sidebarBg)) {
479
+ sidebarBg = isVeryDarkColor(palette.layout.sidebarBg)
480
+ ? "#ffffff"
481
+ : `color-mix(in srgb, ${palette.layout.sidebarBg} 8%, #ffffff)`;
482
+ }
483
+ if (isLightColor(sidebarText)) {
484
+ sidebarText = `color-mix(in srgb, ${palette.layout.sidebarText} 30%, #1e293b)`;
485
+ }
486
+ // If sidebar became light, ensure text is dark for contrast
487
+ if (sidebarBg === "#ffffff" || isLightColor(sidebarBg)) {
488
+ sidebarText = "#334155";
489
+ }
490
+ }
491
+
492
+ styleTag.innerHTML = `
493
+ :root {
494
+ --color-primary: ${palette.primary};
495
+ --color-secondary: ${palette.secondary};
496
+ --color-ternary: ${palette.ternary};
497
+ --color-danger: ${palette.danger};
498
+ --color-success: ${palette.success};
499
+ --color-info: ${palette.info};
500
+ --color-alert: ${palette.alert};
501
+ --color-warning: ${palette.warning};
502
+ --color-heading-default: #1e293b;
503
+ --color-text-default: var(--color-secondary-900);
504
+ --color-text-muted: var(--color-secondary-600);
505
+
506
+ /* Generated scales for primary */
507
+ --color-primary-50: color-mix(in srgb, var(--color-primary) 5%, #ffffff);
508
+ --color-primary-100: color-mix(in srgb, var(--color-primary) 10%, #ffffff);
509
+ --color-primary-200: color-mix(in srgb, var(--color-primary) 30%, #ffffff);
510
+ --color-primary-300: color-mix(in srgb, var(--color-primary) 50%, #ffffff);
511
+ --color-primary-400: color-mix(in srgb, var(--color-primary) 70%, #ffffff);
512
+ --color-primary-500: var(--color-primary);
513
+ --color-primary-600: color-mix(in srgb, var(--color-primary) 85%, #000000);
514
+ --color-primary-700: color-mix(in srgb, var(--color-primary) 70%, #000000);
515
+ --color-primary-800: color-mix(in srgb, var(--color-primary) 55%, #000000);
516
+ --color-primary-900: color-mix(in srgb, var(--color-primary) 40%, #000000);
517
+ --color-primary-950: color-mix(in srgb, var(--color-primary) 25%, #000000);
518
+
519
+ /* Generated scales for secondary */
520
+ --color-secondary-50: color-mix(in srgb, var(--color-secondary) 5%, #ffffff);
521
+ --color-secondary-100: color-mix(in srgb, var(--color-secondary) 10%, #ffffff);
522
+ --color-secondary-200: color-mix(in srgb, var(--color-secondary) 30%, #ffffff);
523
+ --color-secondary-300: color-mix(in srgb, var(--color-secondary) 50%, #ffffff);
524
+ --color-secondary-400: color-mix(in srgb, var(--color-secondary) 70%, #ffffff);
525
+ --color-secondary-500: var(--color-secondary);
526
+ --color-secondary-600: color-mix(in srgb, var(--color-secondary) 85%, #000000);
527
+ --color-secondary-700: color-mix(in srgb, var(--color-secondary) 70%, #000000);
528
+ --color-secondary-800: color-mix(in srgb, var(--color-secondary) 55%, #000000);
529
+ --color-secondary-900: color-mix(in srgb, var(--color-secondary) 40%, #000000);
530
+ --color-secondary-950: color-mix(in srgb, var(--color-secondary) 25%, #000000);
531
+
532
+ /* Generated scales for ternary */
533
+ --color-ternary-50: color-mix(in srgb, var(--color-ternary) 5%, #ffffff);
534
+ --color-ternary-100: color-mix(in srgb, var(--color-ternary) 10%, #ffffff);
535
+ --color-ternary-200: color-mix(in srgb, var(--color-ternary) 30%, #ffffff);
536
+ --color-ternary-300: color-mix(in srgb, var(--color-ternary) 50%, #ffffff);
537
+ --color-ternary-400: color-mix(in srgb, var(--color-ternary) 70%, #ffffff);
538
+ --color-ternary-500: var(--color-ternary);
539
+ --color-ternary-600: color-mix(in srgb, var(--color-ternary) 85%, #000000);
540
+ --color-ternary-700: color-mix(in srgb, var(--color-ternary) 70%, #000000);
541
+ --color-ternary-800: color-mix(in srgb, var(--color-ternary) 55%, #000000);
542
+ --color-ternary-900: color-mix(in srgb, var(--color-ternary) 40%, #000000);
543
+ --color-ternary-950: color-mix(in srgb, var(--color-ternary) 25%, #000000);
544
+
545
+ /* Purple scales mapped as aliases to ternary */
546
+ --color-purple-50: var(--color-ternary-50);
547
+ --color-purple-100: var(--color-ternary-100);
548
+ --color-purple-200: var(--color-ternary-200);
549
+ --color-purple-300: var(--color-ternary-300);
550
+ --color-purple-400: var(--color-ternary-400);
551
+ --color-purple-500: var(--color-ternary-500);
552
+ --color-purple-600: var(--color-ternary-600);
553
+ --color-purple-700: var(--color-ternary-700);
554
+ --color-purple-800: var(--color-ternary-800);
555
+ --color-purple-900: var(--color-ternary-900);
556
+ --color-purple-950: var(--color-ternary-950);
557
+
558
+ /* Generated scales for danger */
559
+ --color-danger-50: color-mix(in srgb, var(--color-danger) 5%, #ffffff);
560
+ --color-danger-100: color-mix(in srgb, var(--color-danger) 10%, #ffffff);
561
+ --color-danger-200: color-mix(in srgb, var(--color-danger) 30%, #ffffff);
562
+ --color-danger-300: color-mix(in srgb, var(--color-danger) 50%, #ffffff);
563
+ --color-danger-400: color-mix(in srgb, var(--color-danger) 70%, #ffffff);
564
+ --color-danger-500: var(--color-danger);
565
+ --color-danger-600: color-mix(in srgb, var(--color-danger) 85%, #000000);
566
+ --color-danger-700: color-mix(in srgb, var(--color-danger) 70%, #000000);
567
+ --color-danger-800: color-mix(in srgb, var(--color-danger) 55%, #000000);
568
+ --color-danger-900: color-mix(in srgb, var(--color-danger) 40%, #000000);
569
+ --color-danger-950: color-mix(in srgb, var(--color-danger) 25%, #000000);
570
+
571
+ /* Generated scales for success */
572
+ --color-success-50: color-mix(in srgb, var(--color-success) 5%, #ffffff);
573
+ --color-success-100: color-mix(in srgb, var(--color-success) 10%, #ffffff);
574
+ --color-success-200: color-mix(in srgb, var(--color-success) 30%, #ffffff);
575
+ --color-success-300: color-mix(in srgb, var(--color-success) 50%, #ffffff);
576
+ --color-success-400: color-mix(in srgb, var(--color-success) 70%, #ffffff);
577
+ --color-success-500: var(--color-success);
578
+ --color-success-600: color-mix(in srgb, var(--color-success) 85%, #000000);
579
+ --color-success-700: color-mix(in srgb, var(--color-success) 70%, #000000);
580
+ --color-success-800: color-mix(in srgb, var(--color-success) 55%, #000000);
581
+ --color-success-900: color-mix(in srgb, var(--color-success) 40%, #000000);
582
+ --color-success-950: color-mix(in srgb, var(--color-success) 25%, #000000);
583
+
584
+ /* Generated scales for info */
585
+ --color-info-50: color-mix(in srgb, var(--color-info) 5%, #ffffff);
586
+ --color-info-100: color-mix(in srgb, var(--color-info) 10%, #ffffff);
587
+ --color-info-200: color-mix(in srgb, var(--color-info) 30%, #ffffff);
588
+ --color-info-300: color-mix(in srgb, var(--color-info) 50%, #ffffff);
589
+ --color-info-400: color-mix(in srgb, var(--color-info) 70%, #ffffff);
590
+ --color-info-500: var(--color-info);
591
+ --color-info-600: color-mix(in srgb, var(--color-info) 85%, #000000);
592
+ --color-info-700: color-mix(in srgb, var(--color-info) 70%, #000000);
593
+ --color-info-800: color-mix(in srgb, var(--color-info) 55%, #000000);
594
+ --color-info-900: color-mix(in srgb, var(--color-info) 40%, #000000);
595
+ --color-info-950: color-mix(in srgb, var(--color-info) 25%, #000000);
596
+
597
+ /* Generated scales for alert */
598
+ --color-alert-50: color-mix(in srgb, var(--color-alert) 5%, #ffffff);
599
+ --color-alert-100: color-mix(in srgb, var(--color-alert) 10%, #ffffff);
600
+ --color-alert-200: color-mix(in srgb, var(--color-alert) 30%, #ffffff);
601
+ --color-alert-300: color-mix(in srgb, var(--color-alert) 50%, #ffffff);
602
+ --color-alert-400: color-mix(in srgb, var(--color-alert) 70%, #ffffff);
603
+ --color-alert-500: var(--color-alert);
604
+ --color-alert-600: color-mix(in srgb, var(--color-alert) 85%, #000000);
605
+ --color-alert-700: color-mix(in srgb, var(--color-alert) 70%, #000000);
606
+ --color-alert-800: color-mix(in srgb, var(--color-alert) 55%, #000000);
607
+ --color-alert-900: color-mix(in srgb, var(--color-alert) 40%, #000000);
608
+ --color-alert-950: color-mix(in srgb, var(--color-alert) 25%, #000000);
609
+
610
+ /* Generated scales for warning */
611
+ --color-warning-50: color-mix(in srgb, var(--color-warning) 5%, #ffffff);
612
+ --color-warning-100: color-mix(in srgb, var(--color-warning) 10%, #ffffff);
613
+ --color-warning-200: color-mix(in srgb, var(--color-warning) 30%, #ffffff);
614
+ --color-warning-300: color-mix(in srgb, var(--color-warning) 50%, #ffffff);
615
+ --color-warning-400: color-mix(in srgb, var(--color-warning) 70%, #ffffff);
616
+ --color-warning-500: var(--color-warning);
617
+ --color-warning-600: color-mix(in srgb, var(--color-warning) 85%, #000000);
618
+ --color-warning-700: color-mix(in srgb, var(--color-warning) 70%, #000000);
619
+ --color-warning-800: color-mix(in srgb, var(--color-warning) 55%, #000000);
620
+ --color-warning-900: color-mix(in srgb, var(--color-warning) 40%, #000000);
621
+ --color-warning-950: color-mix(in srgb, var(--color-warning) 25%, #000000);
622
+
623
+ /* Support legacy client app variables */
624
+ --color-primary-focus: color-mix(in srgb, var(--color-primary) 30%, transparent);
625
+ --color-primary-light: color-mix(in srgb, var(--color-primary) 10%, #ffffff);
626
+ --color-secondary-border: color-mix(in srgb, var(--color-secondary) 30%, #000000);
627
+ --color-ternary-light: color-mix(in srgb, var(--color-ternary) 15%, #ffffff);
628
+ --color-danger-focus: color-mix(in srgb, var(--color-danger) 30%, transparent);
629
+ --color-success-focus: color-mix(in srgb, var(--color-success) 30%, transparent);
630
+ --color-info-focus: color-mix(in srgb, var(--color-info) 30%, transparent);
631
+ --color-alert-focus: color-mix(in srgb, var(--color-alert) 30%, transparent);
632
+ --color-warning-focus: color-mix(in srgb, var(--color-warning) 30%, transparent);
633
+
634
+ /* Map library properties for complete safety */
635
+ --color-primary-hover: color-mix(in srgb, var(--color-primary) 85%, #000000);
636
+ --color-primary-ring: color-mix(in srgb, var(--color-primary) 40%, transparent);
637
+ --color-primary-soft: color-mix(in srgb, var(--color-primary) 12%, transparent);
638
+ --color-primary-soft-border: color-mix(in srgb, var(--color-primary) 24%, transparent);
639
+
640
+ --color-secondary-hover: color-mix(in srgb, var(--color-secondary) 85%, #000000);
641
+ --color-secondary-ring: color-mix(in srgb, var(--color-secondary) 40%, transparent);
642
+ --color-secondary-soft: color-mix(in srgb, var(--color-secondary) 12%, transparent);
643
+ --color-secondary-soft-border: color-mix(in srgb, var(--color-secondary) 24%, transparent);
644
+
645
+ --color-ternary-hover: color-mix(in srgb, var(--color-ternary) 85%, #000000);
646
+ --color-ternary-ring: color-mix(in srgb, var(--color-ternary) 40%, transparent);
647
+ --color-ternary-soft: color-mix(in srgb, var(--color-ternary) 12%, transparent);
648
+ --color-ternary-soft-border: color-mix(in srgb, var(--color-ternary) 24%, transparent);
649
+
650
+ --color-danger-hover: color-mix(in srgb, var(--color-danger) 85%, #000000);
651
+ --color-danger-ring: color-mix(in srgb, var(--color-danger) 40%, transparent);
652
+ --color-danger-soft: color-mix(in srgb, var(--color-danger) 12%, transparent);
653
+ --color-danger-soft-border: color-mix(in srgb, var(--color-danger) 24%, transparent);
654
+
655
+ --color-success-hover: color-mix(in srgb, var(--color-success) 85%, #000000);
656
+ --color-success-ring: color-mix(in srgb, var(--color-success) 40%, transparent);
657
+ --color-success-soft: color-mix(in srgb, var(--color-success) 12%, transparent);
658
+ --color-success-soft-border: color-mix(in srgb, var(--color-success) 24%, transparent);
659
+
660
+ --color-info-hover: color-mix(in srgb, var(--color-info) 85%, #000000);
661
+ --color-info-ring: color-mix(in srgb, var(--color-info) 40%, transparent);
662
+ --color-info-soft: color-mix(in srgb, var(--color-info) 12%, transparent);
663
+ --color-info-soft-border: color-mix(in srgb, var(--color-info) 24%, transparent);
664
+
665
+ --color-alert-hover: color-mix(in srgb, var(--color-alert) 85%, #000000);
666
+ --color-alert-ring: color-mix(in srgb, var(--color-alert) 40%, transparent);
667
+ --color-alert-soft: color-mix(in srgb, var(--color-alert) 12%, transparent);
668
+ --color-alert-soft-border: color-mix(in srgb, var(--color-alert) 24%, transparent);
669
+
670
+ --color-warning-hover: color-mix(in srgb, var(--color-warning) 85%, #000000);
671
+ --color-warning-ring: color-mix(in srgb, var(--color-warning) 40%, transparent);
672
+ --color-warning-soft: color-mix(in srgb, var(--color-warning) 12%, transparent);
673
+ --color-warning-soft-border: color-mix(in srgb, var(--color-warning) 24%, transparent);
674
+
675
+ --color-sidebarBg: ${sidebarBg} !important;
676
+ --color-sidebarText: ${sidebarText} !important;
677
+ --color-navbarBg: ${navbarBg} !important;
678
+ --color-navbarText: ${navbarText} !important;
679
+
680
+ --color-table-headerBg: ${tableHeaderBg} !important;
681
+ --color-table-headerText: ${tableHeaderText} !important;
682
+ --color-table-rowBg: ${tableRowBg} !important;
683
+ --color-table-rowText: ${tableRowText} !important;
684
+
685
+ /* Native library variables integration */
686
+ --sidebar-bg: var(--color-sidebarBg);
687
+ --sidebar-border: color-mix(in srgb, var(--color-sidebarBg) 85%, #000000);
688
+ --sidebar-label-color: var(--color-sidebarText);
689
+ --sidebar-icon-color: color-mix(in srgb, var(--color-sidebarText) 80%, transparent);
690
+ --sidebar-hover-bg: color-mix(in srgb, var(--color-sidebarText) 10%, transparent);
691
+ --sidebar-active-bg: color-mix(in srgb, var(--color-primary) 12%, transparent);
692
+ --sidebar-active-color: var(--color-primary);
693
+ --sidebar-active-icon: var(--color-primary);
694
+ --sidebar-badge-bg: var(--color-primary);
695
+ --sidebar-badge-color: #ffffff;
696
+
697
+ --topbar-bg: var(--color-navbarBg);
698
+ --topbar-text: var(--color-navbarText);
699
+ --topbar-border: color-mix(in srgb, var(--color-navbarBg) 85%, #000000);
700
+ --topbar-icon: color-mix(in srgb, var(--color-navbarText) 80%, transparent);
701
+ --topbar-icon-hover: var(--color-navbarText);
702
+ --topbar-user-bg: var(--topbar-bg);
703
+ --topbar-user-hover: color-mix(in srgb, var(--color-navbarText) 10%, transparent);
704
+ --topbar-user-text: var(--color-navbarText);
705
+ --topbar-user-subtitle: color-mix(in srgb, var(--color-navbarText) 65%, transparent);
706
+ --topbar-user-dropdown-bg: color-mix(in srgb, var(--color-navbarBg) 100%, #ffffff);
707
+ --topbar-user-dropdown-border: color-mix(in srgb, var(--color-navbarBg) 92%, #000000);
708
+ --topbar-user-item-hover: color-mix(in srgb, var(--color-navbarText) 6%, transparent);
709
+
710
+ --layout-bg: var(--color-secondary-50);
711
+ --input-text-color: var(--color-secondary-900);
712
+
713
+ --calendar-selected-bg: var(--color-primary);
714
+ --calendar-selected-text: #ffffff;
715
+ --calendar-range-bg: var(--color-primary-50);
716
+ --calendar-today-bg: var(--color-primary-100);
717
+ --calendar-today-text: var(--color-primary);
718
+ }
719
+
720
+ /* Dark mode overrides */
721
+ .dark, [data-theme="dark"] {
722
+ --color-heading-default: #f8fafc;
723
+ --color-text-default: #cbd5e1;
724
+ --color-text-muted: #64748b;
725
+ --layout-bg: #090f1d;
726
+ --card-bg: #111827;
727
+ --card-border: #1f2937;
728
+ --card-header-bg: #1f2937;
729
+ --card-header-border: #374151;
730
+ --input-bg: #1f2937;
731
+ --input-border: #374151;
732
+ --input-placeholder: #6b7280;
733
+ --input-text-color: #cbd5e1;
734
+ --modal-bg: #111827;
735
+ --modal-footer-bg: #1f2937;
736
+ --modal-header-border: #374151;
737
+ --modal-footer-border: #374151;
738
+ --calendar-bg: #111827;
739
+ --calendar-border: #1f2937;
740
+ --calendar-header-text: #f3f4f6;
741
+ --calendar-header-hover: #1f2937;
742
+ --calendar-days-text: #e5e7eb;
743
+ --calendar-selected-bg: var(--color-primary);
744
+ --calendar-selected-text: #ffffff;
745
+ --calendar-range-bg: var(--color-primary-50);
746
+ --calendar-today-bg: var(--color-primary-100);
747
+ --calendar-today-text: var(--color-primary);
748
+
749
+ /* Override dynamic color-mix scales to blend with dark instead of white */
750
+ --color-primary-50: color-mix(in srgb, var(--color-primary) 10%, #0b1329);
751
+ --color-primary-100: color-mix(in srgb, var(--color-primary) 20%, #0b1329);
752
+ --color-primary-200: color-mix(in srgb, var(--color-primary) 35%, #0b1329);
753
+ --color-primary-300: color-mix(in srgb, var(--color-primary) 50%, #0b1329);
754
+ --color-primary-400: color-mix(in srgb, var(--color-primary) 70%, #0b1329);
755
+
756
+ --color-secondary-50: color-mix(in srgb, var(--color-secondary) 10%, #090f1d);
757
+ --color-secondary-100: color-mix(in srgb, var(--color-secondary) 18%, #090f1d);
758
+ --color-secondary-200: color-mix(in srgb, var(--color-secondary) 30%, #090f1d);
759
+ --color-secondary-300: color-mix(in srgb, var(--color-secondary) 45%, #090f1d);
760
+ --color-secondary-400: color-mix(in srgb, var(--color-secondary) 60%, #090f1d);
761
+
762
+ --color-success-50: color-mix(in srgb, var(--color-success) 10%, #061f14);
763
+ --color-success-100: color-mix(in srgb, var(--color-success) 20%, #061f14);
764
+ --color-success-200: color-mix(in srgb, var(--color-success) 35%, #061f14);
765
+
766
+ --color-danger-50: color-mix(in srgb, var(--color-danger) 10%, #1f0808);
767
+ --color-danger-100: color-mix(in srgb, var(--color-danger) 20%, #1f0808);
768
+ --color-danger-200: color-mix(in srgb, var(--color-danger) 35%, #1f0808);
769
+
770
+ --color-warning-50: color-mix(in srgb, var(--color-warning) 10%, #1f1b05);
771
+ --color-warning-100: color-mix(in srgb, var(--color-warning) 20%, #1f1b05);
772
+ --color-warning-200: color-mix(in srgb, var(--color-warning) 35%, #1f1b05);
773
+
774
+ --color-ternary-50: color-mix(in srgb, var(--color-ternary) 10%, #14081f);
775
+ --color-ternary-100: color-mix(in srgb, var(--color-ternary) 20%, #14081f);
776
+ --color-ternary-200: color-mix(in srgb, var(--color-ternary) 35%, #14081f);
777
+
778
+ --color-info-50: color-mix(in srgb, var(--color-info) 10%, #08141f);
779
+ --color-info-100: color-mix(in srgb, var(--color-info) 20%, #08141f);
780
+ --color-info-200: color-mix(in srgb, var(--color-info) 35%, #08141f);
781
+ }
782
+
783
+ /* Force dark mode class overrides for common backgrounds, borders, and texts */
784
+ .dark, [data-theme="dark"] {
785
+ color: #cbd5e1;
786
+ }
787
+ .dark .text-slate-800, [data-theme="dark"] .text-slate-800,
788
+ .dark .text-gray-800, [data-theme="dark"] .text-gray-800 {
789
+ color: #f8fafc !important;
790
+ }
791
+ .dark .text-slate-700, [data-theme="dark"] .text-slate-700,
792
+ .dark .text-gray-700, [data-theme="dark"] .text-gray-700 {
793
+ color: #cbd5e1 !important;
794
+ }
795
+ .dark .text-slate-600, [data-theme="dark"] .text-slate-600,
796
+ .dark .text-gray-600, [data-theme="dark"] .text-gray-600 {
797
+ color: #cbd5e1 !important;
798
+ }
799
+ .dark .text-slate-500, [data-theme="dark"] .text-slate-500,
800
+ .dark .text-gray-500, [data-theme="dark"] .text-gray-500 {
801
+ color: #94a3b8 !important;
802
+ }
803
+ .dark .text-slate-400, [data-theme="dark"] .text-slate-400,
804
+ .dark .text-gray-400, [data-theme="dark"] .text-gray-400 {
805
+ color: #64748b !important;
806
+ }
807
+
808
+ .dark .bg-white, [data-theme="dark"] .bg-white {
809
+ background-color: var(--card-bg, #111827) !important;
810
+ }
811
+ .dark .bg-slate-50, [data-theme="dark"] .bg-slate-50,
812
+ .dark .bg-gray-50, [data-theme="dark"] .bg-gray-50 {
813
+ background-color: #1f2937 !important;
814
+ }
815
+ .dark .border-slate-100, [data-theme="dark"] .border-slate-100,
816
+ .dark .border-gray-100, [data-theme="dark"] .border-gray-100,
817
+ .dark .border-slate-200, [data-theme="dark"] .border-slate-200,
818
+ .dark .border-gray-200, [data-theme="dark"] .border-gray-200 {
819
+ border-color: #374151 !important;
820
+ }
821
+
822
+ .dark .bg-gray-100, [data-theme="dark"] .bg-gray-100,
823
+ .dark .bg-slate-100, [data-theme="dark"] .bg-slate-100 {
824
+ background-color: #1f2937 !important;
825
+ }
826
+ .dark .border-gray-300, [data-theme="dark"] .border-gray-300,
827
+ .dark .border-slate-300, [data-theme="dark"] .border-slate-300 {
828
+ border-color: #4b5563 !important;
829
+ }
830
+ .dark .bg-gray-200, [data-theme="dark"] .bg-gray-200,
831
+ .dark .bg-slate-200, [data-theme="dark"] .bg-slate-200 {
832
+ background-color: #374151 !important;
833
+ }
834
+
835
+ /* Light mode overrides inside forced light subtree */
836
+ [data-theme="light"] {
837
+ color: #334155;
838
+ --color-text-default: #1e293b;
839
+ --color-text-muted: #475569;
840
+ --layout-bg: var(--color-secondary-50);
841
+ --card-bg: #ffffff;
842
+ --card-border: #f1f5f9;
843
+ --card-header-bg: #f8fafc;
844
+ --card-header-border: #e2e8f0;
845
+ --input-bg: #ffffff;
846
+ --input-border: #cbd5e1;
847
+ --input-placeholder: #94a3b8;
848
+ --input-text-color: #1e293b;
849
+ --modal-bg: #ffffff;
850
+ --modal-footer-bg: #f8fafc;
851
+ --modal-header-border: #e2e8f0;
852
+ --modal-footer-border: #e2e8f0;
853
+ --calendar-bg: #ffffff;
854
+ --calendar-border: #e2e8f0;
855
+ --calendar-header-text: #1e293b;
856
+ --calendar-header-hover: #f1f5f9;
857
+ --calendar-days-text: #334155;
858
+ --calendar-selected-bg: var(--color-primary);
859
+ --calendar-selected-text: #ffffff;
860
+ --calendar-range-bg: var(--color-primary-50);
861
+ --calendar-today-bg: var(--color-primary-100);
862
+ --calendar-today-text: var(--color-primary);
863
+
864
+ --color-primary-50: color-mix(in srgb, var(--color-primary) 5%, #ffffff);
865
+ --color-primary-100: color-mix(in srgb, var(--color-primary) 10%, #ffffff);
866
+ --color-primary-200: color-mix(in srgb, var(--color-primary) 30%, #ffffff);
867
+ --color-primary-300: color-mix(in srgb, var(--color-primary) 50%, #ffffff);
868
+ --color-primary-400: color-mix(in srgb, var(--color-primary) 70%, #ffffff);
869
+
870
+ --color-secondary-50: color-mix(in srgb, var(--color-secondary) 5%, #ffffff);
871
+ --color-secondary-100: color-mix(in srgb, var(--color-secondary) 10%, #ffffff);
872
+ --color-secondary-200: color-mix(in srgb, var(--color-secondary) 30%, #ffffff);
873
+ --color-secondary-300: color-mix(in srgb, var(--color-secondary) 50%, #ffffff);
874
+ --color-secondary-400: color-mix(in srgb, var(--color-secondary) 70%, #ffffff);
875
+
876
+ --color-success-50: color-mix(in srgb, var(--color-success) 5%, #ffffff);
877
+ --color-success-100: color-mix(in srgb, var(--color-success) 10%, #ffffff);
878
+ --color-success-200: color-mix(in srgb, var(--color-success) 30%, #ffffff);
879
+
880
+ --color-danger-50: color-mix(in srgb, var(--color-danger) 5%, #ffffff);
881
+ --color-danger-100: color-mix(in srgb, var(--color-danger) 10%, #ffffff);
882
+ --color-danger-200: color-mix(in srgb, var(--color-danger) 30%, #ffffff);
883
+
884
+ --color-warning-50: color-mix(in srgb, var(--color-warning) 5%, #ffffff);
885
+ --color-warning-100: color-mix(in srgb, var(--color-warning) 10%, #ffffff);
886
+ --color-warning-200: color-mix(in srgb, var(--color-warning) 30%, #ffffff);
887
+
888
+ --color-ternary-50: color-mix(in srgb, var(--color-ternary) 5%, #ffffff);
889
+ --color-ternary-100: color-mix(in srgb, var(--color-ternary) 10%, #ffffff);
890
+ --color-ternary-200: color-mix(in srgb, var(--color-ternary) 30%, #ffffff);
891
+
892
+ --color-info-50: color-mix(in srgb, var(--color-info) 5%, #ffffff);
893
+ --color-info-100: color-mix(in srgb, var(--color-info) 10%, #ffffff);
894
+ --color-info-200: color-mix(in srgb, var(--color-info) 30%, #ffffff);
895
+ }
896
+
897
+ [data-theme="light"] .text-slate-800,
898
+ [data-theme="light"] .text-gray-800 {
899
+ color: #1e293b !important;
900
+ }
901
+ [data-theme="light"] .text-slate-700,
902
+ [data-theme="light"] .text-gray-700 {
903
+ color: #334155 !important;
904
+ }
905
+ [data-theme="light"] .text-slate-600,
906
+ [data-theme="light"] .text-gray-600 {
907
+ color: #475569 !important;
908
+ }
909
+ [data-theme="light"] .text-slate-500,
910
+ [data-theme="light"] .text-gray-500 {
911
+ color: #64748b !important;
912
+ }
913
+ [data-theme="light"] .text-slate-400,
914
+ [data-theme="light"] .text-gray-400 {
915
+ color: #94a3b8 !important;
916
+ }
917
+
918
+ [data-theme="light"] .bg-white {
919
+ background-color: #ffffff !important;
920
+ }
921
+ [data-theme="light"] .bg-slate-50,
922
+ [data-theme="light"] .bg-gray-50 {
923
+ background-color: #f8fafc !important;
924
+ }
925
+ [data-theme="light"] .border-slate-100,
926
+ [data-theme="light"] .border-gray-100,
927
+ [data-theme="light"] .border-slate-200,
928
+ [data-theme="light"] .border-gray-200 {
929
+ border-color: #e2e8f0 !important;
930
+ }
931
+ [data-theme="light"] .bg-gray-100,
932
+ [data-theme="light"] .bg-slate-100 {
933
+ background-color: #f1f5f9 !important;
934
+ }
935
+ [data-theme="light"] .border-gray-300,
936
+ [data-theme="light"] .border-slate-300 {
937
+ border-color: #cbd5e1 !important;
938
+ }
939
+ [data-theme="light"] .bg-gray-200,
940
+ [data-theme="light"] .bg-slate-200 {
941
+ background-color: #e2e8f0 !important;
942
+ }
943
+
944
+
945
+ /* Primary overrides (cyan mappings in UI library) */
946
+ .bg-cyan-400 { background-color: var(--color-primary) !important; }
947
+ .hover\\:bg-cyan-500:hover { background-color: var(--color-primary-hover) !important; }
948
+ .focus\\:ring-cyan-300:focus { --tw-ring-color: var(--color-primary-ring) !important; }
949
+ .text-cyan-600 { color: var(--color-primary) !important; }
950
+ .text-cyan-500 { color: var(--color-primary) !important; }
951
+ .border-cyan-400 { border-color: var(--color-primary) !important; }
952
+ .focus\\:border-cyan-500:focus { border-color: var(--color-primary-hover) !important; }
953
+ .focus\\:ring-cyan-500:focus { --tw-ring-color: var(--color-primary-hover) !important; }
954
+ .text-cyan-100 { color: var(--color-primary-soft) !important; }
955
+ .hover\\:bg-cyan-50:hover { background-color: var(--color-primary-soft) !important; }
956
+
957
+ /* Success overrides (green mappings in UI library) */
958
+ .bg-green-700 { background-color: var(--color-success) !important; }
959
+ .hover\\:bg-green-800:hover { background-color: var(--color-success-hover) !important; }
960
+ .focus\\:ring-green-300:focus { --tw-ring-color: var(--color-success-ring) !important; }
961
+ .text-green-700 { color: var(--color-success) !important; }
962
+ .border-green-700 { border-color: var(--color-success) !important; }
963
+ .bg-green-500 { background-color: var(--color-success) !important; }
964
+ .hover\\:bg-green-600:hover { background-color: var(--color-success-hover) !important; }
965
+
966
+ /* Danger overrides (red mappings in UI library) */
967
+ .bg-red-700 { background-color: var(--color-danger) !important; }
968
+ .hover\\:bg-red-800:hover { background-color: var(--color-danger-hover) !important; }
969
+ .focus\\:ring-red-300:focus { --tw-ring-color: var(--color-danger-ring) !important; }
970
+ .text-red-700 { color: var(--color-danger) !important; }
971
+ .border-red-700 { border-color: var(--color-danger) !important; }
972
+ .bg-red-500 { background-color: var(--color-danger) !important; }
973
+ .hover\\:bg-red-600:hover { background-color: var(--color-danger-hover) !important; }
974
+
975
+ /* Warning overrides (yellow mappings in UI library) */
976
+ .bg-yellow-400 { background-color: var(--color-warning) !important; }
977
+ .hover\\:bg-yellow-500:hover { background-color: var(--color-warning-hover) !important; }
978
+ .focus\\:ring-yellow-300:focus { --tw-ring-color: var(--color-warning-ring) !important; }
979
+ .text-yellow-600 { color: var(--color-warning-hover) !important; }
980
+ .border-yellow-400 { border-color: var(--color-warning) !important; }
981
+ .bg-yellow-500 { background-color: var(--color-warning) !important; }
982
+ .hover\\:bg-yellow-600:hover { background-color: var(--color-warning-hover) !important; }
983
+
984
+ /* Ternary / Orange overrides */
985
+ .bg-orange-500 { background-color: var(--color-ternary) !important; }
986
+ .hover\\:bg-orange-500:hover { background-color: var(--color-ternary-hover) !important; }
987
+ .hover\\:bg-orange-600:hover { background-color: var(--color-ternary-hover) !important; }
988
+ .text-orange-500 { color: var(--color-ternary) !important; }
989
+ .text-orange-800 { color: var(--color-ternary-hover) !important; }
990
+ .bg-orange-200 { background-color: var(--color-ternary-soft) !important; }
991
+ .border-orange-400 { border-color: var(--color-ternary) !important; }
992
+ .border-orange-500 { border-color: var(--color-ternary) !important; }
993
+ .hover\\:bg-orange-50\\/30:hover { background-color: var(--color-ternary-soft) !important; }
994
+
995
+ /* Info / Blue overrides */
996
+ .bg-blue-500 { background-color: var(--color-info) !important; }
997
+ .hover\\:bg-blue-600:hover { background-color: var(--color-info-hover) !important; }
998
+ .text-blue-500 { color: var(--color-info) !important; }
999
+ .text-blue-600 { color: var(--color-info-hover) !important; }
1000
+ .border-blue-500 { border-color: var(--color-info) !important; }
1001
+
1002
+ /* Secondary elements overrides */
1003
+ button[class*="bg-white"][class*="hover:bg-gray-100"] {
1004
+ background-color: var(--color-secondary) !important;
1005
+ border-color: var(--color-secondary-soft-border) !important;
1006
+ color: #111827 !important;
1007
+ }
1008
+ button[class*="bg-white"][class*="hover:bg-gray-100"]:hover {
1009
+ background-color: var(--color-secondary-hover) !important;
1010
+ }
1011
+
1012
+ /* Custom Table styling overrides */
1013
+ thead tr, tr.bg-secondary-50, tr[class*="bg-secondary-50"] {
1014
+ background-color: var(--color-table-headerBg) !important;
1015
+ border-bottom-color: color-mix(in srgb, var(--color-table-headerBg) 85%, #000000) !important;
1016
+ }
1017
+ th span, th div span {
1018
+ color: var(--color-table-headerText) !important;
1019
+ }
1020
+ tbody tr {
1021
+ background-color: var(--color-table-rowBg) !important;
1022
+ }
1023
+ tbody tr td, tbody tr td div {
1024
+ color: var(--color-table-rowText) !important;
1025
+ }
1026
+ tbody tr:hover {
1027
+ background-color: color-mix(in srgb, var(--color-primary) 8%, var(--color-table-rowBg)) !important;
1028
+ }
1029
+
1030
+ /* Animation for Saved Indicator */
1031
+ @keyframes fadeInOut {
1032
+ 0%, 100% { opacity: 0; transform: translateY(-4px); }
1033
+ 15%, 85% { opacity: 1; transform: translateY(0); }
1034
+ }
1035
+ .animate-fade-in-out {
1036
+ animation: fadeInOut 1.5s ease-in-out forwards;
1037
+ }
1038
+
1039
+ /* Fallback utility classes for blurs */
1040
+ .backdrop-blur-xs {
1041
+ backdrop-filter: blur(2px);
1042
+ -webkit-backdrop-filter: blur(2px);
1043
+ }
1044
+ .backdrop-blur-xl {
1045
+ backdrop-filter: blur(24px);
1046
+ -webkit-backdrop-filter: blur(24px);
1047
+ }
1048
+
1049
+ /* =======================================================================
1050
+ AUTONOMOUS THEME DESIGNER STYLES (No Tailwind dependencies)
1051
+ ======================================================================= */
1052
+
1053
+ @keyframes itBounce {
1054
+ 0%, 100% { transform: translateY(0); }
1055
+ 50% { transform: translateY(-8px); }
1056
+ }
1057
+ .it-theme-bounce {
1058
+ animation: itBounce 3s infinite ease-in-out !important;
1059
+ }
1060
+
1061
+ /* FAB styles */
1062
+ .it-theme-fab {
1063
+ position: fixed !important;
1064
+ bottom: 24px !important;
1065
+ right: 24px !important;
1066
+ width: 56px !important;
1067
+ height: 56px !important;
1068
+ border-radius: 50% !important;
1069
+ border: none !important;
1070
+ color: #ffffff !important;
1071
+ box-shadow: 0 4px 14px 0 rgba(0, 0, 0, 0.15) !important;
1072
+ display: flex !important;
1073
+ align-items: center !important;
1074
+ justify-content: center !important;
1075
+ cursor: pointer !important;
1076
+ z-index: 99999 !important;
1077
+ transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.2s ease, box-shadow 0.2s ease !important;
1078
+ outline: none !important;
1079
+ }
1080
+ .it-theme-fab:hover {
1081
+ transform: scale(1.1) !important;
1082
+ box-shadow: 0 6px 20px 0 rgba(0, 0, 0, 0.2) !important;
1083
+ }
1084
+ .it-theme-fab:active {
1085
+ transform: scale(0.95) !important;
1086
+ }
1087
+
1088
+ /* Backdrop styles */
1089
+ .it-theme-backdrop {
1090
+ position: fixed !important;
1091
+ top: 0 !important;
1092
+ left: 0 !important;
1093
+ right: 0 !important;
1094
+ bottom: 0 !important;
1095
+ background-color: rgba(15, 23, 42, 0.3) !important;
1096
+ backdrop-filter: blur(4px) !important;
1097
+ -webkit-backdrop-filter: blur(4px) !important;
1098
+ z-index: 99997 !important;
1099
+ transition: opacity 0.3s ease !important;
1100
+ }
1101
+
1102
+ /* Drawer container */
1103
+ .it-theme-drawer {
1104
+ position: fixed !important;
1105
+ top: 0 !important;
1106
+ right: 0 !important;
1107
+ bottom: 0 !important;
1108
+ width: 100% !important;
1109
+ max-width: 420px !important;
1110
+ background-color: #ffffff !important;
1111
+ box-shadow: -10px 0 25px -5px rgba(0, 0, 0, 0.08), -8px 0 10px -6px rgba(0, 0, 0, 0.08) !important;
1112
+ z-index: 99998 !important;
1113
+ display: flex !important;
1114
+ flex-direction: column !important;
1115
+ justify-content: space-between !important;
1116
+ padding: 24px !important;
1117
+ box-sizing: border-box !important;
1118
+ border-left: 1px solid rgba(226, 232, 240, 0.8) !important;
1119
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
1120
+ font-family: Inter, system-ui, -apple-system, sans-serif !important;
1121
+ color: #1e293b !important;
1122
+ }
1123
+
1124
+ .dark .it-theme-drawer, [data-theme="dark"] .it-theme-drawer {
1125
+ background-color: #0f172a !important;
1126
+ border-left-color: rgba(30, 41, 59, 0.8) !important;
1127
+ color: #f1f5f9 !important;
1128
+ }
1129
+
1130
+ /* Drawer Header */
1131
+ .it-theme-drawer-header {
1132
+ display: flex !important;
1133
+ align-items: center !important;
1134
+ justify-content: space-between !important;
1135
+ padding-bottom: 16px !important;
1136
+ border-bottom: 1px solid #e2e8f0 !important;
1137
+ }
1138
+ .dark .it-theme-drawer-header, [data-theme="dark"] .it-theme-drawer-header {
1139
+ border-bottom-color: #1e293b !important;
1140
+ }
1141
+
1142
+ .it-theme-drawer-title-group {
1143
+ display: flex !important;
1144
+ align-items: center !important;
1145
+ gap: 12px !important;
1146
+ }
1147
+
1148
+ .it-theme-icon-container {
1149
+ width: 36px !important;
1150
+ height: 36px !important;
1151
+ border-radius: 8px !important;
1152
+ display: flex !important;
1153
+ align-items: center !important;
1154
+ justify-content: center !important;
1155
+ color: #ffffff !important;
1156
+ }
1157
+
1158
+ .it-theme-drawer-title {
1159
+ font-size: 16px !important;
1160
+ font-weight: 700 !important;
1161
+ margin: 0 !important;
1162
+ color: #1e293b !important;
1163
+ line-height: 1.2 !important;
1164
+ }
1165
+ .dark .it-theme-drawer-title, [data-theme="dark"] .it-theme-drawer-title {
1166
+ color: #f8fafc !important;
1167
+ }
1168
+
1169
+ .it-theme-drawer-subtitle {
1170
+ font-size: 11px !important;
1171
+ color: #64748b !important;
1172
+ margin: 2px 0 0 0 !important;
1173
+ font-weight: 400 !important;
1174
+ }
1175
+ .dark .it-theme-drawer-subtitle, [data-theme="dark"] .it-theme-drawer-subtitle {
1176
+ color: #94a3b8 !important;
1177
+ }
1178
+
1179
+ .it-theme-close-btn {
1180
+ background: none !important;
1181
+ border: none !important;
1182
+ color: #94a3b8 !important;
1183
+ cursor: pointer !important;
1184
+ padding: 6px !important;
1185
+ border-radius: 6px !important;
1186
+ display: flex !important;
1187
+ align-items: center !important;
1188
+ justify-content: center !important;
1189
+ transition: background-color 0.2s, color 0.2s !important;
1190
+ }
1191
+ .it-theme-close-btn:hover {
1192
+ background-color: #f1f5f9 !important;
1193
+ color: #334155 !important;
1194
+ }
1195
+ .dark .it-theme-close-btn:hover, [data-theme="dark"] .it-theme-close-btn:hover {
1196
+ background-color: #1e293b !important;
1197
+ color: #f1f5f9 !important;
1198
+ }
1199
+
1200
+ /* Sections inside Drawer */
1201
+ .it-theme-section {
1202
+ margin-top: 18px !important;
1203
+ }
1204
+
1205
+ .it-theme-section-title {
1206
+ font-size: 10px !important;
1207
+ font-weight: 700 !important;
1208
+ text-transform: uppercase !important;
1209
+ letter-spacing: 0.05em !important;
1210
+ color: #94a3b8 !important;
1211
+ margin-bottom: 8px !important;
1212
+ margin-top: 0 !important;
1213
+ }
1214
+
1215
+ /* Preset Grid */
1216
+ .it-theme-presets-grid {
1217
+ display: grid !important;
1218
+ grid-template-columns: repeat(2, 1fr) !important;
1219
+ gap: 8px !important;
1220
+ }
1221
+
1222
+ .it-theme-preset-card {
1223
+ display: flex !important;
1224
+ flex-direction: column !important;
1225
+ align-items: flex-start !important;
1226
+ padding: 10px !important;
1227
+ border-radius: 10px !important;
1228
+ border: 1px solid #e2e8f0 !important;
1229
+ background-color: rgba(255, 255, 255, 0.6) !important;
1230
+ cursor: pointer !important;
1231
+ text-align: left !important;
1232
+ transition: all 0.2s ease !important;
1233
+ width: 100% !important;
1234
+ box-sizing: border-box !important;
1235
+ }
1236
+ .dark .it-theme-preset-card, [data-theme="dark"] .it-theme-preset-card {
1237
+ border-color: #1e293b !important;
1238
+ background-color: rgba(15, 23, 42, 0.4) !important;
1239
+ }
1240
+
1241
+ .it-theme-preset-card:hover {
1242
+ border-color: #cbd5e1 !important;
1243
+ transform: translateY(-1px) !important;
1244
+ }
1245
+ .dark .it-theme-preset-card:hover, [data-theme="dark"] .it-theme-preset-card:hover {
1246
+ border-color: #334155 !important;
1247
+ }
1248
+
1249
+ .it-theme-preset-name {
1250
+ font-size: 11px !important;
1251
+ font-weight: 600 !important;
1252
+ color: #334155 !important;
1253
+ margin-bottom: 6px !important;
1254
+ margin-top: 0 !important;
1255
+ white-space: nowrap !important;
1256
+ overflow: hidden !important;
1257
+ text-overflow: ellipsis !important;
1258
+ width: 100% !important;
1259
+ }
1260
+ .dark .it-theme-preset-name, [data-theme="dark"] .it-theme-preset-name {
1261
+ color: #cbd5e1 !important;
1262
+ }
1263
+
1264
+ .it-theme-preset-colors {
1265
+ display: flex !important;
1266
+ gap: 4px !important;
1267
+ }
1268
+
1269
+ .it-theme-preset-dot {
1270
+ width: 12px !important;
1271
+ height: 12px !important;
1272
+ border-radius: 50% !important;
1273
+ border: 1px solid rgba(0,0,0,0.08) !important;
1274
+ }
1275
+
1276
+ /* Color controls list */
1277
+ .it-theme-color-list {
1278
+ display: flex !important;
1279
+ flex-direction: column !important;
1280
+ gap: 6px !important;
1281
+ max-height: 250px !important;
1282
+ overflow-y: auto !important;
1283
+ padding-right: 4px !important;
1284
+ }
1285
+
1286
+ .it-theme-color-row {
1287
+ display: flex !important;
1288
+ align-items: center !important;
1289
+ justify-content: space-between !important;
1290
+ padding: 6px 10px !important;
1291
+ border-radius: 10px !important;
1292
+ border: 1px solid #f1f5f9 !important;
1293
+ background-color: rgba(248, 250, 252, 0.5) !important;
1294
+ }
1295
+ .dark .it-theme-color-row, [data-theme="dark"] .it-theme-color-row {
1296
+ border-color: #1e293b !important;
1297
+ background-color: rgba(9, 15, 29, 0.5) !important;
1298
+ }
1299
+
1300
+ .it-theme-color-left {
1301
+ display: flex !important;
1302
+ align-items: center !important;
1303
+ gap: 12px !important;
1304
+ }
1305
+
1306
+ .it-theme-color-picker-btn {
1307
+ position: relative !important;
1308
+ width: 28px !important;
1309
+ height: 28px !important;
1310
+ border-radius: 50% !important;
1311
+ overflow: hidden !important;
1312
+ border: 1px solid #cbd5e1 !important;
1313
+ box-shadow: inset 0 2px 4px 0 rgba(0,0,0,0.06) !important;
1314
+ cursor: pointer !important;
1315
+ display: flex !important;
1316
+ align-items: center !important;
1317
+ justify-content: center !important;
1318
+ }
1319
+ .dark .it-theme-color-picker-btn, [data-theme="dark"] .it-theme-color-picker-btn {
1320
+ border-color: #475569 !important;
1321
+ }
1322
+
1323
+ .it-theme-color-picker-input {
1324
+ position: absolute !important;
1325
+ top: 0 !important;
1326
+ left: 0 !important;
1327
+ width: 100% !important;
1328
+ height: 100% !important;
1329
+ opacity: 0 !important;
1330
+ cursor: pointer !important;
1331
+ margin: 0 !important;
1332
+ padding: 0 !important;
1333
+ }
1334
+
1335
+ .it-theme-color-picker-preview {
1336
+ width: 100% !important;
1337
+ height: 100% !important;
1338
+ border-radius: 50% !important;
1339
+ }
1340
+
1341
+ .it-theme-color-meta {
1342
+ display: flex !important;
1343
+ flex-direction: column !important;
1344
+ }
1345
+
1346
+ .it-theme-color-label {
1347
+ font-size: 10px !important;
1348
+ font-weight: 700 !important;
1349
+ text-transform: uppercase !important;
1350
+ color: #475569 !important;
1351
+ }
1352
+ .dark .it-theme-color-label, [data-theme="dark"] .it-theme-color-label {
1353
+ color: #cbd5e1 !important;
1354
+ }
1355
+
1356
+ .it-theme-color-hex-text {
1357
+ font-family: monospace !important;
1358
+ font-size: 9px !important;
1359
+ color: #94a3b8 !important;
1360
+ margin-top: 1px !important;
1361
+ }
1362
+
1363
+ .it-theme-color-text-input {
1364
+ width: 80px !important;
1365
+ padding: 4px 6px !important;
1366
+ font-size: 11px !important;
1367
+ font-family: monospace !important;
1368
+ text-align: center !important;
1369
+ border-radius: 6px !important;
1370
+ border: 1px solid #cbd5e1 !important;
1371
+ background-color: #ffffff !important;
1372
+ color: #334155 !important;
1373
+ outline: none !important;
1374
+ transition: border-color 0.2s !important;
1375
+ box-sizing: border-box !important;
1376
+ }
1377
+ .dark .it-theme-color-text-input, [data-theme="dark"] .it-theme-color-text-input {
1378
+ border-color: #475569 !important;
1379
+ background-color: #1e293b !important;
1380
+ color: #cbd5e1 !important;
1381
+ }
1382
+
1383
+ /* Mode Selector Segmented Control */
1384
+ .it-theme-mode-selector {
1385
+ display: grid !important;
1386
+ grid-template-columns: repeat(3, 1fr) !important;
1387
+ gap: 2px !important;
1388
+ background-color: #f1f5f9 !important;
1389
+ padding: 2px !important;
1390
+ border-radius: 8px !important;
1391
+ width: 180px !important;
1392
+ }
1393
+ .dark .it-theme-mode-selector, [data-theme="dark"] .it-theme-mode-selector {
1394
+ background-color: #1e293b !important;
1395
+ }
1396
+
1397
+ .it-theme-mode-btn {
1398
+ background: none !important;
1399
+ border: none !important;
1400
+ padding: 6px 8px !important;
1401
+ font-size: 11px !important;
1402
+ font-weight: 600 !important;
1403
+ color: #475569 !important;
1404
+ border-radius: 6px !important;
1405
+ cursor: pointer !important;
1406
+ text-align: center !important;
1407
+ transition: all 0.2s ease !important;
1408
+ }
1409
+ .dark .it-theme-mode-btn, [data-theme="dark"] .it-theme-mode-btn {
1410
+ color: #94a3b8 !important;
1411
+ }
1412
+
1413
+ .it-theme-mode-btn-active {
1414
+ background-color: #ffffff !important;
1415
+ color: var(--color-primary) !important;
1416
+ box-shadow: 0 1px 3px rgba(0,0,0,0.06) !important;
1417
+ }
1418
+ .dark .it-theme-mode-btn-active, [data-theme="dark"] .it-theme-mode-btn-active {
1419
+ background-color: #0f172a !important;
1420
+ color: var(--color-primary) !important;
1421
+ }
1422
+
1423
+ /* Saved notification toast */
1424
+ .it-theme-toast-container {
1425
+ height: 20px !important;
1426
+ margin: 6px 0 !important;
1427
+ position: relative !important;
1428
+ }
1429
+
1430
+ .it-theme-toast {
1431
+ position: absolute !important;
1432
+ top: 0 !important;
1433
+ left: 0 !important;
1434
+ right: 0 !important;
1435
+ display: flex !important;
1436
+ justify-content: center !important;
1437
+ }
1438
+
1439
+ .it-theme-toast-badge {
1440
+ display: inline-flex !important;
1441
+ align-items: center !important;
1442
+ gap: 4px !important;
1443
+ font-size: 10px !important;
1444
+ font-weight: 600 !important;
1445
+ background-color: rgba(34, 197, 94, 0.1) !important;
1446
+ color: #16a34a !important;
1447
+ padding: 3px 10px !important;
1448
+ border-radius: 9999px !important;
1449
+ border: 1px solid rgba(34, 197, 94, 0.2) !important;
1450
+ }
1451
+
1452
+ /* Drawer Footer */
1453
+ .it-theme-drawer-footer {
1454
+ padding-top: 12px !important;
1455
+ margin-top: 12px !important;
1456
+ border-top: 1px solid #e2e8f0 !important;
1457
+ display: flex !important;
1458
+ align-items: center !important;
1459
+ justify-content: space-between !important;
1460
+ }
1461
+ .dark .it-theme-drawer-footer, [data-theme="dark"] .it-theme-drawer-footer {
1462
+ border-top-color: #1e293b !important;
1463
+ }
1464
+
1465
+ .it-theme-reset-btn {
1466
+ display: flex !important;
1467
+ align-items: center !important;
1468
+ gap: 6px !important;
1469
+ padding: 6px 12px !important;
1470
+ font-size: 11px !important;
1471
+ font-weight: 600 !important;
1472
+ background: none !important;
1473
+ border: none !important;
1474
+ border-radius: 6px !important;
1475
+ color: #64748b !important;
1476
+ cursor: pointer !important;
1477
+ transition: background-color 0.2s, color 0.2s !important;
1478
+ }
1479
+ .it-theme-reset-btn:hover {
1480
+ background-color: #f1f5f9 !important;
1481
+ color: #1e293b !important;
1482
+ }
1483
+ .dark .it-theme-reset-btn:hover, [data-theme="dark"] .it-theme-reset-btn:hover {
1484
+ background-color: #1e293b !important;
1485
+ color: #f8fafc !important;
1486
+ }
1487
+
1488
+ .it-theme-done-btn {
1489
+ padding: 6px 16px !important;
1490
+ font-size: 11px !important;
1491
+ font-weight: 700 !important;
1492
+ border: none !important;
1493
+ border-radius: 6px !important;
1494
+ color: #ffffff !important;
1495
+ cursor: pointer !important;
1496
+ box-shadow: 0 2px 4px rgba(0,0,0,0.05) !important;
1497
+ transition: transform 0.2s, background-color 0.2s !important;
1498
+ }
1499
+ .it-theme-done-btn:hover {
1500
+ transform: translateY(-1px) !important;
1501
+ }
1502
+
1503
+ h1, h2, h3 {
1504
+ color: var(--color-heading-default);
1505
+ }
1506
+ `;
1507
+
1508
+ }, [palette, resolvedTheme]);
1509
+
1510
+ const updateColor = (key: string, value: string) => {
1511
+ setPaletteState((prev) => {
1512
+ if (key.includes(".")) {
1513
+ const [section, subKey] = key.split(".");
1514
+ return {
1515
+ ...prev,
1516
+ [section]: {
1517
+ ...(prev[section as keyof ITThemePalette] as Record<
1518
+ string,
1519
+ string
1520
+ >),
1521
+ [subKey]: value,
1522
+ },
1523
+ };
1524
+ }
1525
+ return {
1526
+ ...prev,
1527
+ [key]: value,
1528
+ };
1529
+ });
1530
+ };
1531
+
1532
+ const applyPreset = (colors: ITThemePalette) => {
1533
+ setPaletteState(colors);
1534
+ };
1535
+
1536
+ const resetTheme = () => {
1537
+ const basePalette = {
1538
+ ...DEFAULT_PALETTE,
1539
+ ...theme,
1540
+ layout: { ...DEFAULT_PALETTE.layout, ...theme?.layout },
1541
+ table: { ...DEFAULT_PALETTE.table, ...theme?.table },
1542
+ };
1543
+ setPaletteState(basePalette as ITThemePalette);
1544
+ };
1545
+
1546
+ const ColorRow = ({ colorKey }: { colorKey: string }) => {
1547
+ const isNested = colorKey.includes(".");
1548
+ const label = isNested ? colorKey.split(".")[1] : colorKey;
1549
+ const value = getNestedValue(palette, colorKey);
1550
+
1551
+ return (
1552
+ <div
1553
+ key={colorKey}
1554
+ className="flex items-center justify-between p-3 rounded-xl border border-slate-100 dark:border-slate-800 bg-white dark:bg-slate-900/50 gap-3 hover:border-slate-200 dark:hover:border-slate-700 transition-colors"
1555
+ >
1556
+ <div className="flex items-center gap-3 flex-1 min-w-0">
1557
+ <div className="relative w-10 h-10 rounded-xl border-2 border-slate-200 dark:border-slate-700 overflow-hidden cursor-pointer flex-shrink-0 shadow-sm hover:scale-105 transition-transform">
1558
+ <input
1559
+ type="color"
1560
+ value={value}
1561
+ onChange={(e) => updateColor(colorKey, e.target.value)}
1562
+ className="absolute inset-0 opacity-0 cursor-pointer w-full h-full"
1563
+ />
1564
+ <div className="w-full h-full" style={{ backgroundColor: value }} />
1565
+ </div>
1566
+ <div className="flex flex-col min-w-0">
1567
+ <ITText as="span" className="text-xs font-bold text-slate-700 dark:text-slate-300 truncate capitalize">
1568
+ {label.replace(/([A-Z])/g, " $1").trim()}
1569
+ </ITText>
1570
+ <div className="flex items-center gap-2 mt-0.5">
1571
+ <span
1572
+ className="w-3 h-3 rounded-full border border-slate-200 dark:border-slate-600"
1573
+ style={{ backgroundColor: value }}
1574
+ />
1575
+ <ITText as="span" className="font-mono text-[11px] text-slate-400">{value}</ITText>
1576
+ </div>
1577
+ </div>
1578
+ </div>
1579
+ <input
1580
+ type="text"
1581
+ value={value}
1582
+ onChange={(e) => updateColor(colorKey, e.target.value)}
1583
+ className="w-24 px-2.5 py-1.5 text-xs font-mono text-center rounded-lg border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-300 outline-none focus:ring-2 focus:ring-primary-500/40 focus:border-primary-500 transition-all"
1584
+ />
1585
+ </div>
1586
+ );
1587
+ };
1588
+
1589
+ const PresetCard = ({
1590
+ preset,
1591
+ isCustom,
1592
+ }: {
1593
+ preset: { name: string; colors: ITThemePalette };
1594
+ isCustom?: boolean;
1595
+ }) => {
1596
+ const isSelected =
1597
+ JSON.stringify(preset.colors) === JSON.stringify(palette);
1598
+ return (
1599
+ <button
1600
+ type="button"
1601
+ onClick={() => applyPreset(preset.colors)}
1602
+ className={`relative flex flex-col items-start p-2.5 rounded-xl border text-left transition-all group ${
1603
+ isSelected
1604
+ ? "border-primary-500 bg-primary-500/5 shadow-sm ring-1 ring-primary-500/20"
1605
+ : "border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900/50 hover:border-slate-300 dark:hover:border-slate-600"
1606
+ }`}
1607
+ >
1608
+ {isCustom && (
1609
+ <span
1610
+ onClick={(e) => {
1611
+ e.stopPropagation();
1612
+ handleDeletePreset(preset.name, e);
1613
+ }}
1614
+ className="absolute top-1.5 right-1.5 opacity-0 group-hover:opacity-100 p-0.5 rounded-md hover:bg-red-500/10 hover:text-red-500 text-slate-400 dark:text-slate-500 cursor-pointer transition-all z-10"
1615
+ title="Eliminar"
1616
+ >
1617
+ <MdClose size={12} />
1618
+ </span>
1619
+ )}
1620
+ <ITText as="span" className="text-xs font-semibold truncate w-full mb-1.5 pr-4 text-slate-700 dark:text-slate-300">
1621
+ {preset.name}
1622
+ </ITText>
1623
+ <div className="flex gap-1">
1624
+ {(["primary", "secondary", "ternary", "success"] as const).map((c) => (
1625
+ <span
1626
+ key={c}
1627
+ className="w-3 h-3 rounded-full border border-black/10"
1628
+ style={{ backgroundColor: preset.colors[c] }}
1629
+ />
1630
+ ))}
1631
+ </div>
1632
+ </button>
1633
+ );
1634
+ };
1635
+
1636
+ return (
1637
+ <ITThemeContext.Provider
1638
+ value={{
1639
+ palette,
1640
+ colors: palette,
1641
+ setPalette: setPaletteState,
1642
+ updateColor,
1643
+ resetTheme,
1644
+ applyPreset,
1645
+ resolvedTheme,
1646
+ darkModeMode,
1647
+ setDarkModeMode,
1648
+ }}
1649
+ >
1650
+ {children}
1651
+
1652
+ {showFab && (
1653
+ <button
1654
+ onClick={() => setIsOpen((prev) => !prev)}
1655
+ className="it-theme-fab it-theme-bounce"
1656
+ style={{ backgroundColor: "var(--color-primary)" }}
1657
+ aria-label="Configurar Paleta de Colores"
1658
+ >
1659
+ <MdPalette size={28} />
1660
+ </button>
1661
+ )}
1662
+
1663
+ {showFab && (
1664
+ <ITDialog
1665
+ isOpen={isOpen}
1666
+ onClose={() => setIsOpen(false)}
1667
+ title="Diseñador de Temas"
1668
+ useFormHeader
1669
+ >
1670
+ <div className="flex gap-6 h-[580px]">
1671
+ {/* LEFT: Mode + Presets */}
1672
+ <div className="w-64 flex-shrink-0 flex flex-col gap-5 overflow-y-auto pr-1">
1673
+ <div>
1674
+ <ITText as="span" className="text-[11px] font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500 mb-2.5 block">
1675
+ Apariencia
1676
+ </ITText>
1677
+ <ITSegmentedControl
1678
+ options={[
1679
+ { value: "light", label: "☀️" },
1680
+ { value: "dark", label: "🌙" },
1681
+ { value: "system", label: "💻" },
1682
+ ]}
1683
+ value={darkModeMode}
1684
+ onChange={(val) => setDarkModeMode(val as "dark" | "light" | "system")}
1685
+ size="sm"
1686
+ />
1687
+ </div>
1688
+
1689
+ <div>
1690
+ <div className="flex items-center justify-between mb-2.5">
1691
+ <ITText as="span" className="text-[11px] font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500">
1692
+ Presets
1693
+ </ITText>
1694
+ </div>
1695
+ <div className="grid grid-cols-2 gap-2">
1696
+ {PRESETS.map((preset) => (
1697
+ <PresetCard key={preset.name} preset={preset} />
1698
+ ))}
1699
+ </div>
1700
+ </div>
1701
+
1702
+ {customPresets.length > 0 && (
1703
+ <div>
1704
+ <ITText as="span" className="text-[11px] font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500 mb-2.5 block">
1705
+ Mis Temas
1706
+ </ITText>
1707
+ <div className="flex flex-col gap-1.5">
1708
+ {customPresets.map((preset) => (
1709
+ <PresetCard key={preset.name} preset={preset} isCustom />
1710
+ ))}
1711
+ </div>
1712
+ </div>
1713
+ )}
1714
+
1715
+ {/* Save preset inline */}
1716
+ {isSavingPreset && (
1717
+ <div className="flex flex-col gap-2 p-3 rounded-xl border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900/50">
1718
+ <ITInput
1719
+ name="presetName"
1720
+ placeholder="Nombre del tema..."
1721
+ value={newPresetName}
1722
+ onChange={(e: any) => setNewPresetName(e.target.value)}
1723
+ containerClassName="mb-0"
1724
+ className="text-xs"
1725
+ onKeyDown={(e: React.KeyboardEvent) => {
1726
+ if (e.key === "Enter") handleSavePreset();
1727
+ if (e.key === "Escape") {
1728
+ setIsSavingPreset(false);
1729
+ setNewPresetName("");
1730
+ }
1731
+ }}
1732
+ />
1733
+ <div className="flex gap-2">
1734
+ <ITButton
1735
+ label="Guardar"
1736
+ color="primary"
1737
+ onClick={handleSavePreset}
1738
+ disabled={!newPresetName.trim()}
1739
+ size="small"
1740
+ className="flex-1"
1741
+ />
1742
+ <ITButton
1743
+ label="X"
1744
+ variant="ghost"
1745
+ onClick={() => {
1746
+ setIsSavingPreset(false);
1747
+ setNewPresetName("");
1748
+ }}
1749
+ size="small"
1750
+ />
1751
+ </div>
1752
+ </div>
1753
+ )}
1754
+
1755
+ {!isSavingPreset && (
1756
+ <ITButton
1757
+ variant="outlined"
1758
+ icon={<MdPalette size={14} />}
1759
+ label="Guardar actual"
1760
+ onClick={() => setIsSavingPreset(true)}
1761
+ size="small"
1762
+ />
1763
+ )}
1764
+
1765
+ <ITButton
1766
+ variant="outlined"
1767
+ color="danger"
1768
+ icon={<MdRefresh size={14} />}
1769
+ label="Restaurar default"
1770
+ onClick={resetTheme}
1771
+ size="small"
1772
+ />
1773
+ </div>
1774
+
1775
+ <ITDivider orientation="vertical" />
1776
+
1777
+ {/* RIGHT: Color editor */}
1778
+ <div className="flex-1 flex flex-col min-w-0">
1779
+ <ITTabs
1780
+ variant="pill"
1781
+ items={[
1782
+ {
1783
+ id: "brand",
1784
+ label: "Marca",
1785
+ content: (
1786
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-3 max-h-[480px] overflow-y-auto pr-2 mt-3">
1787
+ {[
1788
+ "primary",
1789
+ "secondary",
1790
+ "ternary",
1791
+ "danger",
1792
+ "success",
1793
+ "info",
1794
+ "alert",
1795
+ "warning",
1796
+ ].map((key) => (
1797
+ <ColorRow key={key} colorKey={key} />
1798
+ ))}
1799
+ </div>
1800
+ ),
1801
+ },
1802
+ {
1803
+ id: "layout",
1804
+ label: "Nav & Sidebar",
1805
+ content: (
1806
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-3 max-h-[480px] overflow-y-auto pr-2 mt-3">
1807
+ {[
1808
+ "layout.sidebarBg",
1809
+ "layout.sidebarText",
1810
+ "layout.navbarBg",
1811
+ "layout.navbarText",
1812
+ ].map((key) => (
1813
+ <ColorRow key={key} colorKey={key} />
1814
+ ))}
1815
+ </div>
1816
+ ),
1817
+ },
1818
+ {
1819
+ id: "tables",
1820
+ label: "Tablas",
1821
+ content: (
1822
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-3 max-h-[480px] overflow-y-auto pr-2 mt-3">
1823
+ {[
1824
+ "table.headerBg",
1825
+ "table.headerText",
1826
+ "table.rowBg",
1827
+ "table.rowText",
1828
+ ].map((key) => (
1829
+ <ColorRow key={key} colorKey={key} />
1830
+ ))}
1831
+ </div>
1832
+ ),
1833
+ },
1834
+ ]}
1835
+ />
1836
+
1837
+ <div className="flex items-center justify-end gap-3 mt-auto pt-4 border-t border-slate-100 dark:border-slate-800">
1838
+ <ITText as="p" className="text-[11px] text-slate-400 mr-auto">
1839
+ Los cambios se guardan automáticamente
1840
+ </ITText>
1841
+ <ITButton
1842
+ label="Cerrar"
1843
+ color="primary"
1844
+ onClick={() => setIsOpen(false)}
1845
+ size="small"
1846
+ />
1847
+ </div>
1848
+ </div>
1849
+ </div>
1850
+ </ITDialog>
1851
+ )}
1852
+ </ITThemeContext.Provider>
1853
+ );
1854
+ }