@jjlmoya/utils-developer 1.2.0

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 (228) hide show
  1. package/package.json +64 -0
  2. package/src/category/i18n/en.ts +34 -0
  3. package/src/category/i18n/es.ts +34 -0
  4. package/src/category/i18n/fr.ts +34 -0
  5. package/src/category/index.ts +31 -0
  6. package/src/category/seo.astro +15 -0
  7. package/src/components/PreviewNavSidebar.astro +116 -0
  8. package/src/components/PreviewToolbar.astro +143 -0
  9. package/src/data.ts +11 -0
  10. package/src/env.d.ts +5 -0
  11. package/src/index.ts +78 -0
  12. package/src/layouts/PreviewLayout.astro +117 -0
  13. package/src/pages/[locale]/[slug].astro +146 -0
  14. package/src/pages/[locale].astro +251 -0
  15. package/src/pages/index.astro +4 -0
  16. package/src/tests/css_specificity_logic.test.ts +39 -0
  17. package/src/tests/faq_count.test.ts +19 -0
  18. package/src/tests/locale_completeness.test.ts +42 -0
  19. package/src/tests/mocks/astro_mock.js +2 -0
  20. package/src/tests/no_h1_in_components.test.ts +48 -0
  21. package/src/tests/schemas_fulfillment.test.ts +23 -0
  22. package/src/tests/seo_length.test.ts +22 -0
  23. package/src/tests/title_quality.test.ts +55 -0
  24. package/src/tests/tool_validation.test.ts +17 -0
  25. package/src/tool/aspectRatio/bibliography.astro +14 -0
  26. package/src/tool/aspectRatio/component.astro +468 -0
  27. package/src/tool/aspectRatio/i18n/en.ts +177 -0
  28. package/src/tool/aspectRatio/i18n/es.ts +177 -0
  29. package/src/tool/aspectRatio/i18n/fr.ts +177 -0
  30. package/src/tool/aspectRatio/index.ts +34 -0
  31. package/src/tool/aspectRatio/seo.astro +14 -0
  32. package/src/tool/aspectRatio/ui.ts +12 -0
  33. package/src/tool/calculadoraTiempoDatos/bibliography.astro +14 -0
  34. package/src/tool/calculadoraTiempoDatos/component.astro +829 -0
  35. package/src/tool/calculadoraTiempoDatos/i18n/en.ts +150 -0
  36. package/src/tool/calculadoraTiempoDatos/i18n/es.ts +163 -0
  37. package/src/tool/calculadoraTiempoDatos/i18n/fr.ts +150 -0
  38. package/src/tool/calculadoraTiempoDatos/index.ts +33 -0
  39. package/src/tool/calculadoraTiempoDatos/seo.astro +14 -0
  40. package/src/tool/calculadoraTiempoDatos/ui.ts +24 -0
  41. package/src/tool/colorConverter/bibliography.astro +14 -0
  42. package/src/tool/colorConverter/component.astro +504 -0
  43. package/src/tool/colorConverter/i18n/en.ts +126 -0
  44. package/src/tool/colorConverter/i18n/es.ts +126 -0
  45. package/src/tool/colorConverter/i18n/fr.ts +126 -0
  46. package/src/tool/colorConverter/index.ts +33 -0
  47. package/src/tool/colorConverter/seo.astro +14 -0
  48. package/src/tool/colorConverter/ui.ts +16 -0
  49. package/src/tool/conversorExcelCsvHtml/bibliography.astro +14 -0
  50. package/src/tool/conversorExcelCsvHtml/component.astro +595 -0
  51. package/src/tool/conversorExcelCsvHtml/i18n/en.ts +129 -0
  52. package/src/tool/conversorExcelCsvHtml/i18n/es.ts +129 -0
  53. package/src/tool/conversorExcelCsvHtml/i18n/fr.ts +129 -0
  54. package/src/tool/conversorExcelCsvHtml/index.ts +33 -0
  55. package/src/tool/conversorExcelCsvHtml/seo.astro +14 -0
  56. package/src/tool/conversorExcelCsvHtml/ui.ts +14 -0
  57. package/src/tool/cronGenerator/bibliography.astro +14 -0
  58. package/src/tool/cronGenerator/component.astro +667 -0
  59. package/src/tool/cronGenerator/i18n/en.ts +191 -0
  60. package/src/tool/cronGenerator/i18n/es.ts +191 -0
  61. package/src/tool/cronGenerator/i18n/fr.ts +191 -0
  62. package/src/tool/cronGenerator/index.ts +34 -0
  63. package/src/tool/cronGenerator/seo.astro +14 -0
  64. package/src/tool/cronGenerator/ui.ts +45 -0
  65. package/src/tool/cssSpecificityCalculator/bibliography.astro +14 -0
  66. package/src/tool/cssSpecificityCalculator/component.astro +292 -0
  67. package/src/tool/cssSpecificityCalculator/i18n/en.ts +168 -0
  68. package/src/tool/cssSpecificityCalculator/i18n/es.ts +168 -0
  69. package/src/tool/cssSpecificityCalculator/i18n/fr.ts +168 -0
  70. package/src/tool/cssSpecificityCalculator/index.ts +34 -0
  71. package/src/tool/cssSpecificityCalculator/logic.ts +100 -0
  72. package/src/tool/cssSpecificityCalculator/seo.astro +14 -0
  73. package/src/tool/cssSpecificityCalculator/ui-controller.ts +57 -0
  74. package/src/tool/cssSpecificityCalculator/ui.ts +11 -0
  75. package/src/tool/cssToInlineConverter/bibliography.astro +14 -0
  76. package/src/tool/cssToInlineConverter/component.astro +308 -0
  77. package/src/tool/cssToInlineConverter/i18n/en.ts +160 -0
  78. package/src/tool/cssToInlineConverter/i18n/es.ts +160 -0
  79. package/src/tool/cssToInlineConverter/i18n/fr.ts +160 -0
  80. package/src/tool/cssToInlineConverter/index.ts +34 -0
  81. package/src/tool/cssToInlineConverter/seo.astro +14 -0
  82. package/src/tool/cssToInlineConverter/ui.ts +12 -0
  83. package/src/tool/duplicateCssRemover/bibliography.astro +14 -0
  84. package/src/tool/duplicateCssRemover/component.astro +353 -0
  85. package/src/tool/duplicateCssRemover/i18n/en.ts +167 -0
  86. package/src/tool/duplicateCssRemover/i18n/es.ts +167 -0
  87. package/src/tool/duplicateCssRemover/i18n/fr.ts +167 -0
  88. package/src/tool/duplicateCssRemover/index.ts +34 -0
  89. package/src/tool/duplicateCssRemover/seo.astro +14 -0
  90. package/src/tool/duplicateCssRemover/ui.ts +12 -0
  91. package/src/tool/generadorSecurityTxt/bibliography.astro +14 -0
  92. package/src/tool/generadorSecurityTxt/component.astro +473 -0
  93. package/src/tool/generadorSecurityTxt/i18n/en.ts +173 -0
  94. package/src/tool/generadorSecurityTxt/i18n/es.ts +173 -0
  95. package/src/tool/generadorSecurityTxt/i18n/fr.ts +173 -0
  96. package/src/tool/generadorSecurityTxt/index.ts +33 -0
  97. package/src/tool/generadorSecurityTxt/seo.astro +14 -0
  98. package/src/tool/generadorSecurityTxt/ui.ts +27 -0
  99. package/src/tool/hashGenerator/bibliography.astro +14 -0
  100. package/src/tool/hashGenerator/component.astro +367 -0
  101. package/src/tool/hashGenerator/i18n/en.ts +118 -0
  102. package/src/tool/hashGenerator/i18n/es.ts +118 -0
  103. package/src/tool/hashGenerator/i18n/fr.ts +118 -0
  104. package/src/tool/hashGenerator/index.ts +33 -0
  105. package/src/tool/hashGenerator/md5.ts +138 -0
  106. package/src/tool/hashGenerator/seo.astro +14 -0
  107. package/src/tool/hashGenerator/ui.ts +11 -0
  108. package/src/tool/inspectorCertificadosSsl/bibliography.astro +14 -0
  109. package/src/tool/inspectorCertificadosSsl/component.astro +580 -0
  110. package/src/tool/inspectorCertificadosSsl/i18n/en.ts +214 -0
  111. package/src/tool/inspectorCertificadosSsl/i18n/es.ts +214 -0
  112. package/src/tool/inspectorCertificadosSsl/i18n/fr.ts +214 -0
  113. package/src/tool/inspectorCertificadosSsl/index.ts +33 -0
  114. package/src/tool/inspectorCertificadosSsl/seo.astro +14 -0
  115. package/src/tool/inspectorCertificadosSsl/ui.ts +29 -0
  116. package/src/tool/jsonFormatter/bibliography.astro +14 -0
  117. package/src/tool/jsonFormatter/component.astro +590 -0
  118. package/src/tool/jsonFormatter/i18n/en.ts +156 -0
  119. package/src/tool/jsonFormatter/i18n/es.ts +156 -0
  120. package/src/tool/jsonFormatter/i18n/fr.ts +156 -0
  121. package/src/tool/jsonFormatter/index.ts +34 -0
  122. package/src/tool/jsonFormatter/seo.astro +14 -0
  123. package/src/tool/jsonFormatter/ui.ts +15 -0
  124. package/src/tool/keycode/bibliography.astro +14 -0
  125. package/src/tool/keycode/component.astro +540 -0
  126. package/src/tool/keycode/i18n/en.ts +160 -0
  127. package/src/tool/keycode/i18n/es.ts +160 -0
  128. package/src/tool/keycode/i18n/fr.ts +160 -0
  129. package/src/tool/keycode/index.ts +34 -0
  130. package/src/tool/keycode/seo.astro +14 -0
  131. package/src/tool/keycode/ui.ts +10 -0
  132. package/src/tool/llmCostCalculator/bibliography.astro +14 -0
  133. package/src/tool/llmCostCalculator/component.astro +488 -0
  134. package/src/tool/llmCostCalculator/data.ts +99 -0
  135. package/src/tool/llmCostCalculator/i18n/en.ts +165 -0
  136. package/src/tool/llmCostCalculator/i18n/es.ts +165 -0
  137. package/src/tool/llmCostCalculator/i18n/fr.ts +165 -0
  138. package/src/tool/llmCostCalculator/index.ts +34 -0
  139. package/src/tool/llmCostCalculator/seo.astro +14 -0
  140. package/src/tool/llmCostCalculator/ui.ts +11 -0
  141. package/src/tool/mobileMockupGenerator/app.ts +614 -0
  142. package/src/tool/mobileMockupGenerator/bibliography.astro +14 -0
  143. package/src/tool/mobileMockupGenerator/component.astro +1044 -0
  144. package/src/tool/mobileMockupGenerator/constants.ts +48 -0
  145. package/src/tool/mobileMockupGenerator/i18n/en.ts +121 -0
  146. package/src/tool/mobileMockupGenerator/i18n/es.ts +121 -0
  147. package/src/tool/mobileMockupGenerator/i18n/fr.ts +121 -0
  148. package/src/tool/mobileMockupGenerator/index.ts +33 -0
  149. package/src/tool/mobileMockupGenerator/rendering.ts +189 -0
  150. package/src/tool/mobileMockupGenerator/seo.astro +14 -0
  151. package/src/tool/mobileMockupGenerator/store.ts +145 -0
  152. package/src/tool/mobileMockupGenerator/types.ts +41 -0
  153. package/src/tool/mobileMockupGenerator/ui.ts +48 -0
  154. package/src/tool/musicalTypography/bibliography.astro +14 -0
  155. package/src/tool/musicalTypography/component.astro +480 -0
  156. package/src/tool/musicalTypography/i18n/en.ts +179 -0
  157. package/src/tool/musicalTypography/i18n/es.ts +179 -0
  158. package/src/tool/musicalTypography/i18n/fr.ts +179 -0
  159. package/src/tool/musicalTypography/index.ts +33 -0
  160. package/src/tool/musicalTypography/seo.astro +14 -0
  161. package/src/tool/musicalTypography/ui.ts +25 -0
  162. package/src/tool/placeholderGenerator/bibliography.astro +14 -0
  163. package/src/tool/placeholderGenerator/component.astro +499 -0
  164. package/src/tool/placeholderGenerator/i18n/en.ts +176 -0
  165. package/src/tool/placeholderGenerator/i18n/es.ts +176 -0
  166. package/src/tool/placeholderGenerator/i18n/fr.ts +176 -0
  167. package/src/tool/placeholderGenerator/index.ts +34 -0
  168. package/src/tool/placeholderGenerator/seo.astro +14 -0
  169. package/src/tool/placeholderGenerator/ui.ts +14 -0
  170. package/src/tool/promptLibrary/bibliography.astro +14 -0
  171. package/src/tool/promptLibrary/component.astro +1131 -0
  172. package/src/tool/promptLibrary/controller.ts +49 -0
  173. package/src/tool/promptLibrary/i18n/en.ts +131 -0
  174. package/src/tool/promptLibrary/i18n/es.ts +131 -0
  175. package/src/tool/promptLibrary/i18n/fr.ts +126 -0
  176. package/src/tool/promptLibrary/index.ts +33 -0
  177. package/src/tool/promptLibrary/seo.astro +14 -0
  178. package/src/tool/promptLibrary/ui.ts +29 -0
  179. package/src/tool/readabilityCalculator/bibliography.astro +14 -0
  180. package/src/tool/readabilityCalculator/component.astro +534 -0
  181. package/src/tool/readabilityCalculator/i18n/en.ts +133 -0
  182. package/src/tool/readabilityCalculator/i18n/es.ts +133 -0
  183. package/src/tool/readabilityCalculator/i18n/fr.ts +133 -0
  184. package/src/tool/readabilityCalculator/index.ts +33 -0
  185. package/src/tool/readabilityCalculator/seo.astro +14 -0
  186. package/src/tool/readabilityCalculator/ui.ts +27 -0
  187. package/src/tool/svgSanitizer/bibliography.astro +14 -0
  188. package/src/tool/svgSanitizer/component.astro +554 -0
  189. package/src/tool/svgSanitizer/i18n/en.ts +125 -0
  190. package/src/tool/svgSanitizer/i18n/es.ts +125 -0
  191. package/src/tool/svgSanitizer/i18n/fr.ts +125 -0
  192. package/src/tool/svgSanitizer/index.ts +33 -0
  193. package/src/tool/svgSanitizer/seo.astro +14 -0
  194. package/src/tool/svgSanitizer/ui.ts +18 -0
  195. package/src/tool/svgToCss/bibliography.astro +14 -0
  196. package/src/tool/svgToCss/component.astro +381 -0
  197. package/src/tool/svgToCss/i18n/en.ts +174 -0
  198. package/src/tool/svgToCss/i18n/es.ts +174 -0
  199. package/src/tool/svgToCss/i18n/fr.ts +174 -0
  200. package/src/tool/svgToCss/index.ts +34 -0
  201. package/src/tool/svgToCss/seo.astro +14 -0
  202. package/src/tool/svgToCss/ui.ts +13 -0
  203. package/src/tool/urlCleaner/bibliography.astro +14 -0
  204. package/src/tool/urlCleaner/component.astro +458 -0
  205. package/src/tool/urlCleaner/i18n/en.ts +116 -0
  206. package/src/tool/urlCleaner/i18n/es.ts +116 -0
  207. package/src/tool/urlCleaner/i18n/fr.ts +116 -0
  208. package/src/tool/urlCleaner/index.ts +33 -0
  209. package/src/tool/urlCleaner/seo.astro +14 -0
  210. package/src/tool/urlCleaner/ui.ts +12 -0
  211. package/src/tool/urlEncoderDecoder/bibliography.astro +14 -0
  212. package/src/tool/urlEncoderDecoder/component.astro +291 -0
  213. package/src/tool/urlEncoderDecoder/i18n/en.ts +162 -0
  214. package/src/tool/urlEncoderDecoder/i18n/es.ts +162 -0
  215. package/src/tool/urlEncoderDecoder/i18n/fr.ts +162 -0
  216. package/src/tool/urlEncoderDecoder/index.ts +34 -0
  217. package/src/tool/urlEncoderDecoder/seo.astro +14 -0
  218. package/src/tool/urlEncoderDecoder/ui.ts +11 -0
  219. package/src/tool/utmGenerator/bibliography.astro +14 -0
  220. package/src/tool/utmGenerator/component.astro +270 -0
  221. package/src/tool/utmGenerator/i18n/en.ts +117 -0
  222. package/src/tool/utmGenerator/i18n/es.ts +117 -0
  223. package/src/tool/utmGenerator/i18n/fr.ts +117 -0
  224. package/src/tool/utmGenerator/index.ts +33 -0
  225. package/src/tool/utmGenerator/seo.astro +14 -0
  226. package/src/tool/utmGenerator/ui.ts +13 -0
  227. package/src/tools.ts +27 -0
  228. package/src/types.ts +72 -0
@@ -0,0 +1,595 @@
1
+ ---
2
+ import { Icon } from 'astro-icon/components';
3
+ import type { KnownLocale } from '../../types';
4
+ import type { ConversorExcelCsvHtmlUI } from './ui';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ ui?: Record<string, unknown>;
9
+ }
10
+
11
+ const { ui } = Astro.props;
12
+ const content = (ui ?? {}) as ConversorExcelCsvHtmlUI;
13
+ ---
14
+
15
+ <div class="cec-container">
16
+ <div class="cec-converter-card">
17
+ <div class="cec-input-grid">
18
+ <div class="cec-input-group">
19
+ <label class="cec-input-label" for="csvInput">{content.csvInputLabel}</label>
20
+ <textarea
21
+ id="csvInput"
22
+ class="cec-csv-textarea"
23
+ placeholder={content.csvInputPlaceholder}
24
+ ></textarea>
25
+ </div>
26
+ <div class="cec-input-group">
27
+ <label class="cec-input-label">{content.uploadLabel}</label>
28
+ <div class="cec-drop-zone" id="dropZone">
29
+ <Icon name="mdi:cloud-upload-outline" size={48} />
30
+ <span>{content.dragDropLabel}</span>
31
+ <input type="file" id="fileInput" accept=".csv" style="display: none" />
32
+ </div>
33
+ </div>
34
+ </div>
35
+
36
+ <div class="cec-options-row">
37
+ <label class="cec-option-item">
38
+ <input type="checkbox" id="hasHeader" checked />
39
+ <span>{content.headerCheckboxLabel}</span>
40
+ </label>
41
+ <label class="cec-option-item">
42
+ <input type="checkbox" id="addBorders" />
43
+ <span>{content.bordersCheckboxLabel}</span>
44
+ </label>
45
+ <label class="cec-option-item">
46
+ <input type="checkbox" id="zebraStripes" checked />
47
+ <span>{content.stripeCheckboxLabel}</span>
48
+ </label>
49
+ </div>
50
+ </div>
51
+
52
+ <div class="cec-results-section">
53
+ <div class="cec-result-tabs">
54
+ <button class="cec-tab-btn cec-tab-active" data-tab="preview">{content.previewTabLabel}</button>
55
+ <button class="cec-tab-btn" data-tab="code">{content.codeTabLabel}</button>
56
+ </div>
57
+
58
+ <div id="previewTab" class="cec-tab-content">
59
+ <div class="cec-preview-container" id="previewOutput">
60
+ <div class="cec-empty-state">
61
+ <Icon name="mdi:table-off" size={48} />
62
+ <p>{content.emptyStateLabel}</p>
63
+ </div>
64
+ </div>
65
+ </div>
66
+
67
+ <div id="codeTab" class="cec-tab-content" style="display: none;">
68
+ <div class="cec-code-container">
69
+ <textarea id="htmlOutput" class="cec-code-textarea" readonly></textarea>
70
+ <button id="copyBtn" class="cec-copy-btn">
71
+ <Icon name="mdi:content-copy" />
72
+ {content.copyButtonLabel}
73
+ </button>
74
+ </div>
75
+ </div>
76
+ </div>
77
+ </div>
78
+
79
+ <script>
80
+ const csvInput = document.getElementById('csvInput') as HTMLTextAreaElement;
81
+ const dropZone = document.getElementById('dropZone');
82
+ const fileInput = document.getElementById('fileInput') as HTMLInputElement;
83
+ const hasHeader = document.getElementById('hasHeader') as HTMLInputElement;
84
+ const addBorders = document.getElementById('addBorders') as HTMLInputElement;
85
+ const zebraStripes = document.getElementById('zebraStripes') as HTMLInputElement;
86
+ const previewOutput = document.getElementById('previewOutput');
87
+ const htmlOutput = document.getElementById('htmlOutput') as HTMLTextAreaElement;
88
+ const copyBtn = document.getElementById('copyBtn');
89
+ const tabs = document.querySelectorAll('.cec-tab-btn');
90
+ const tabContents = document.querySelectorAll('.cec-tab-content');
91
+
92
+ function parseCSV(text: string) {
93
+ if (!text.trim()) return [];
94
+
95
+ const lines = text.trim().split(/\r\n|\n/);
96
+ return lines.map(line => {
97
+ const values: string[] = [];
98
+ let current = '';
99
+ let inQuotes = false;
100
+
101
+ for (let i = 0; i < line.length; i++) {
102
+ const char = line[i];
103
+ if (char === '"') {
104
+ inQuotes = !inQuotes;
105
+ } else if (char === ',' && !inQuotes) {
106
+ values.push(current.trim());
107
+ current = '';
108
+ } else {
109
+ current += char;
110
+ }
111
+ }
112
+ values.push(current.trim());
113
+ return values.map(v => v.replace(/^"|"$/g, '').replace(/""/g, '"'));
114
+ });
115
+ }
116
+
117
+ function generateHTML(data: string[][]) {
118
+ if (data.length === 0) return '';
119
+
120
+ let html = '<table';
121
+ const classes = [];
122
+ if (addBorders.checked) classes.push('bordered');
123
+ if (zebraStripes.checked) classes.push('zebra');
124
+
125
+ if (classes.length > 0) {
126
+ html += ` class="${classes.join(' ')}"`;
127
+ }
128
+ html += '>\n';
129
+
130
+ let startIndex = 0;
131
+ if (hasHeader.checked && data.length > 0) {
132
+ html += ' <thead>\n <tr>\n';
133
+ data[0].forEach(cell => {
134
+ html += ` <th>${cell}</th>\n`;
135
+ });
136
+ html += ' </tr>\n </thead>\n';
137
+ startIndex = 1;
138
+ }
139
+
140
+ html += ' <tbody>\n';
141
+ for (let i = startIndex; i < data.length; i++) {
142
+ html += ' <tr>\n';
143
+ data[i].forEach(cell => {
144
+ html += ` <td>${cell}</td>\n`;
145
+ });
146
+ html += ' </tr>\n';
147
+ }
148
+ html += ' </tbody>\n</table>';
149
+
150
+ return html;
151
+ }
152
+
153
+ function update() {
154
+ const text = csvInput.value;
155
+ const data = parseCSV(text);
156
+ const html = generateHTML(data);
157
+
158
+ if (html) {
159
+ if (previewOutput) previewOutput.innerHTML = html;
160
+ htmlOutput.value = html;
161
+ } else {
162
+ if (previewOutput) {
163
+ previewOutput.innerHTML = `
164
+ <div class="cec-empty-state">
165
+ <Icon name="mdi:table-off" size={48} />
166
+ <p>Introduce datos para ver la tabla</p>
167
+ </div>
168
+ `;
169
+ }
170
+ htmlOutput.value = '';
171
+ }
172
+ }
173
+
174
+ csvInput.addEventListener('input', update);
175
+ [hasHeader, addBorders, zebraStripes].forEach(el => el.addEventListener('change', update));
176
+
177
+ dropZone?.addEventListener('click', () => fileInput.click());
178
+
179
+ dropZone?.addEventListener('dragover', (e) => {
180
+ e.preventDefault();
181
+ dropZone.classList.add('cec-dragover');
182
+ });
183
+
184
+ dropZone?.addEventListener('dragleave', () => {
185
+ dropZone.classList.remove('cec-dragover');
186
+ });
187
+
188
+ dropZone?.addEventListener('drop', (e) => {
189
+ e.preventDefault();
190
+ dropZone.classList.remove('cec-dragover');
191
+ const file = e.dataTransfer?.files[0];
192
+ if (file) handleFile(file);
193
+ });
194
+
195
+ fileInput.addEventListener('change', (e) => {
196
+ const file = (e.target as HTMLInputElement).files?.[0];
197
+ if (file) handleFile(file);
198
+ });
199
+
200
+ function handleFile(file: File) {
201
+ const reader = new FileReader();
202
+ reader.onload = (e) => {
203
+ const text = e.target?.result as string;
204
+ csvInput.value = text;
205
+ update();
206
+ };
207
+ reader.readAsText(file);
208
+ }
209
+
210
+ tabs.forEach(tab => {
211
+ tab.addEventListener('click', () => {
212
+ tabs.forEach(t => t.classList.remove('cec-tab-active'));
213
+ tab.classList.add('cec-tab-active');
214
+
215
+ const target = (tab as HTMLElement).dataset.tab;
216
+ tabContents.forEach(content => {
217
+ if (content.id === `${target}Tab`) {
218
+ (content as HTMLElement).style.display = 'block';
219
+ } else {
220
+ (content as HTMLElement).style.display = 'none';
221
+ }
222
+ });
223
+ });
224
+ });
225
+
226
+ copyBtn?.addEventListener('click', () => {
227
+ navigator.clipboard.writeText(htmlOutput.value);
228
+ const originalText = copyBtn.innerHTML;
229
+ copyBtn.innerHTML = '<Icon name="mdi:check" /> ¡Copiado!';
230
+ setTimeout(() => {
231
+ copyBtn.innerHTML = originalText;
232
+ }, 2000);
233
+ });
234
+ </script>
235
+
236
+ <style scoped>
237
+ :root {
238
+ --cec-primary: rgb(139, 92, 246);
239
+ --cec-primary-hover: rgb(124, 58, 202);
240
+ --cec-border: rgb(226, 232, 240);
241
+ --cec-border-dark: rgb(51, 65, 85);
242
+ --cec-bg-light: rgb(248, 250, 252);
243
+ --cec-bg-dark: rgb(15, 23, 42);
244
+ --cec-text-primary: rgb(30, 41, 59);
245
+ --cec-text-secondary: rgb(71, 85, 105);
246
+ --cec-text-light: rgb(241, 245, 249);
247
+ }
248
+
249
+ .cec-container {
250
+ display: flex;
251
+ flex-direction: column;
252
+ gap: 2rem;
253
+ width: 100%;
254
+ max-width: 1000px;
255
+ margin: 0 auto;
256
+ }
257
+
258
+ .cec-converter-card {
259
+ background: rgba(255, 255, 255, 0.7);
260
+ backdrop-filter: blur(20px);
261
+ border: 1px solid rgba(255, 255, 255, 0.3);
262
+ border-radius: 24px;
263
+ padding: 2rem;
264
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.05);
265
+ }
266
+
267
+ :global(.theme-dark) .cec-converter-card {
268
+ background: rgba(15, 23, 42, 0.6);
269
+ border-color: rgba(255, 255, 255, 0.05);
270
+ }
271
+
272
+ .cec-input-grid {
273
+ display: grid;
274
+ grid-template-columns: 1fr;
275
+ gap: 1.5rem;
276
+ }
277
+
278
+ @media (min-width: 768px) {
279
+ .cec-input-grid {
280
+ grid-template-columns: 1fr 1fr;
281
+ }
282
+ }
283
+
284
+ .cec-input-group {
285
+ display: flex;
286
+ flex-direction: column;
287
+ gap: 0.75rem;
288
+ }
289
+
290
+ .cec-input-label {
291
+ font-size: 0.875rem;
292
+ font-weight: 700;
293
+ color: var(--cec-text-secondary);
294
+ text-transform: uppercase;
295
+ letter-spacing: 0.05em;
296
+ }
297
+
298
+ :global(.theme-dark) .cec-input-label {
299
+ color: rgb(148, 163, 184);
300
+ }
301
+
302
+ .cec-csv-textarea {
303
+ width: 100%;
304
+ height: 200px;
305
+ background: white;
306
+ border: 1px solid var(--cec-border);
307
+ border-radius: 12px;
308
+ padding: 1rem;
309
+ font-size: 0.875rem;
310
+ color: var(--cec-text-primary);
311
+ resize: vertical;
312
+ transition: all 0.2s;
313
+ }
314
+
315
+ :global(.theme-dark) .cec-csv-textarea {
316
+ background: rgb(2, 6, 23);
317
+ border-color: rgb(30, 41, 59);
318
+ color: var(--cec-text-light);
319
+ }
320
+
321
+ .cec-csv-textarea:focus {
322
+ outline: none;
323
+ border-color: var(--cec-primary);
324
+ box-shadow: 0 0 0 4px rgba(139, 92, 246, 0.1);
325
+ }
326
+
327
+ .cec-drop-zone {
328
+ border: 2px dashed var(--cec-border);
329
+ border-radius: 12px;
330
+ height: 200px;
331
+ display: flex;
332
+ flex-direction: column;
333
+ align-items: center;
334
+ justify-content: center;
335
+ gap: 1rem;
336
+ cursor: pointer;
337
+ transition: all 0.2s;
338
+ background: rgba(248, 250, 252, 0.5);
339
+ }
340
+
341
+ :global(.theme-dark) .cec-drop-zone {
342
+ border-color: var(--cec-border-dark);
343
+ background: rgba(30, 41, 59, 0.2);
344
+ }
345
+
346
+ .cec-drop-zone:hover,
347
+ .cec-dragover {
348
+ border-color: var(--cec-primary);
349
+ background: rgba(139, 92, 246, 0.05);
350
+ }
351
+
352
+ .cec-drop-zone :global(svg) {
353
+ color: var(--cec-primary);
354
+ }
355
+
356
+ .cec-drop-zone span {
357
+ font-size: 0.875rem;
358
+ color: rgb(100, 116, 139);
359
+ font-weight: 500;
360
+ }
361
+
362
+ .cec-options-row {
363
+ display: flex;
364
+ flex-wrap: wrap;
365
+ gap: 1.5rem;
366
+ margin-top: 1rem;
367
+ padding-top: 1.5rem;
368
+ border-top: 1px solid rgba(0, 0, 0, 0.05);
369
+ }
370
+
371
+ :global(.theme-dark) .cec-options-row {
372
+ border-top-color: rgba(255, 255, 255, 0.05);
373
+ }
374
+
375
+ .cec-option-item {
376
+ display: flex;
377
+ align-items: center;
378
+ gap: 0.75rem;
379
+ cursor: pointer;
380
+ position: relative;
381
+ user-select: none;
382
+ padding: 0.5rem 0.75rem;
383
+ border-radius: 12px;
384
+ transition: background-color 0.2s;
385
+ }
386
+
387
+ .cec-option-item:hover {
388
+ background: rgba(139, 92, 246, 0.05);
389
+ }
390
+
391
+ .cec-option-item input[type="checkbox"] {
392
+ appearance: none;
393
+ width: 20px;
394
+ height: 20px;
395
+ border: 2px solid var(--cec-border);
396
+ border-radius: 6px;
397
+ background: white;
398
+ cursor: pointer;
399
+ position: relative;
400
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
401
+ }
402
+
403
+ :global(.theme-dark) .cec-option-item input[type="checkbox"] {
404
+ background: rgb(15, 23, 42);
405
+ border-color: var(--cec-border-dark);
406
+ }
407
+
408
+ .cec-option-item input[type="checkbox"]:checked {
409
+ background: var(--cec-primary);
410
+ border-color: var(--cec-primary);
411
+ box-shadow: 0 4px 6px -1px rgba(139, 92, 246, 0.2);
412
+ }
413
+
414
+ .cec-option-item input[type="checkbox"]:checked::after {
415
+ content: '';
416
+ position: absolute;
417
+ left: 6px;
418
+ top: 2px;
419
+ width: 5px;
420
+ height: 10px;
421
+ border: solid white;
422
+ border-width: 0 2px 2px 0;
423
+ transform: rotate(45deg);
424
+ }
425
+
426
+ .cec-option-item span {
427
+ font-size: 0.9rem;
428
+ font-weight: 600;
429
+ color: var(--cec-text-secondary);
430
+ }
431
+
432
+ :global(.theme-dark) .cec-option-item span {
433
+ color: rgb(148, 163, 184);
434
+ }
435
+
436
+ .cec-option-item input[type="checkbox"]:checked + span {
437
+ color: rgb(88, 28, 135);
438
+ }
439
+
440
+ :global(.theme-dark) .cec-option-item input[type="checkbox"]:checked + span {
441
+ color: rgb(196, 181, 253);
442
+ }
443
+
444
+ .cec-results-section {
445
+ display: flex;
446
+ flex-direction: column;
447
+ gap: 1.5rem;
448
+ }
449
+
450
+ .cec-result-tabs {
451
+ display: flex;
452
+ gap: 0.5rem;
453
+ border-bottom: 2px solid var(--cec-border);
454
+ }
455
+
456
+ :global(.theme-dark) .cec-result-tabs {
457
+ border-bottom-color: rgb(30, 41, 59);
458
+ }
459
+
460
+ .cec-tab-btn {
461
+ padding: 0.75rem 1.5rem;
462
+ font-size: 0.875rem;
463
+ font-weight: 700;
464
+ color: rgb(100, 116, 139);
465
+ background: transparent;
466
+ border: none;
467
+ cursor: pointer;
468
+ border-bottom: 2px solid transparent;
469
+ margin-bottom: -2px;
470
+ transition: all 0.2s;
471
+ }
472
+
473
+ .cec-tab-active {
474
+ color: var(--cec-primary);
475
+ border-bottom-color: var(--cec-primary);
476
+ }
477
+
478
+ .cec-preview-container {
479
+ background: white;
480
+ border: 1px solid var(--cec-border);
481
+ border-radius: 12px;
482
+ overflow-x: auto;
483
+ max-height: 400px;
484
+ padding: 1rem;
485
+ }
486
+
487
+ :global(.theme-dark) .cec-preview-container {
488
+ background: rgb(15, 23, 42);
489
+ border-color: rgb(30, 41, 59);
490
+ }
491
+
492
+ .cec-code-container {
493
+ position: relative;
494
+ }
495
+
496
+ .cec-code-textarea {
497
+ width: 100%;
498
+ height: 300px;
499
+ background: rgb(30, 41, 59);
500
+ color: rgb(226, 232, 240);
501
+ border-radius: 12px;
502
+ padding: 1.5rem;
503
+ font-size: 0.875rem;
504
+ resize: vertical;
505
+ border: none;
506
+ }
507
+
508
+ .cec-copy-btn {
509
+ position: absolute;
510
+ top: 1rem;
511
+ right: 1rem;
512
+ background: var(--cec-primary);
513
+ color: white;
514
+ border: none;
515
+ border-radius: 8px;
516
+ padding: 0.5rem 1rem;
517
+ font-size: 0.75rem;
518
+ font-weight: 700;
519
+ cursor: pointer;
520
+ display: flex;
521
+ align-items: center;
522
+ gap: 0.5rem;
523
+ transition: all 0.2s;
524
+ }
525
+
526
+ .cec-copy-btn:hover {
527
+ background: var(--cec-primary-hover);
528
+ }
529
+
530
+ .cec-preview-container :global(table) {
531
+ width: 100%;
532
+ border-collapse: collapse;
533
+ font-size: 0.875rem;
534
+ }
535
+
536
+ .cec-preview-container :global(th) {
537
+ background: var(--cec-bg-light);
538
+ border-bottom: 2px solid var(--cec-border);
539
+ padding: 0.75rem;
540
+ text-align: left;
541
+ font-weight: 700;
542
+ color: var(--cec-text-primary);
543
+ }
544
+
545
+ :global(.theme-dark) .cec-preview-container :global(th) {
546
+ background: rgb(30, 41, 59);
547
+ border-bottom-color: var(--cec-border-dark);
548
+ color: var(--cec-text-light);
549
+ }
550
+
551
+ .cec-preview-container :global(td) {
552
+ padding: 0.75rem;
553
+ border-bottom: 1px solid rgb(241, 245, 249);
554
+ color: var(--cec-text-secondary);
555
+ }
556
+
557
+ :global(.theme-dark) .cec-preview-container :global(td) {
558
+ border-bottom-color: rgb(30, 41, 59);
559
+ color: rgb(148, 163, 184);
560
+ }
561
+
562
+ .cec-empty-state {
563
+ display: flex;
564
+ flex-direction: column;
565
+ align-items: center;
566
+ justify-content: center;
567
+ padding: 3rem;
568
+ color: rgb(148, 163, 184);
569
+ text-align: center;
570
+ gap: 1rem;
571
+ }
572
+
573
+ .cec-preview-container :global(table.bordered) {
574
+ border: 1px solid var(--cec-border);
575
+ }
576
+
577
+ .cec-preview-container :global(table.bordered th),
578
+ .cec-preview-container :global(table.bordered td) {
579
+ border: 1px solid var(--cec-border);
580
+ }
581
+
582
+ :global(.theme-dark) .cec-preview-container :global(table.bordered),
583
+ :global(.theme-dark) .cec-preview-container :global(table.bordered th),
584
+ :global(.theme-dark) .cec-preview-container :global(table.bordered td) {
585
+ border-color: var(--cec-border-dark);
586
+ }
587
+
588
+ .cec-preview-container :global(table.zebra tbody tr:nth-child(even)) {
589
+ background: var(--cec-bg-light);
590
+ }
591
+
592
+ :global(.theme-dark) .cec-preview-container :global(table.zebra tbody tr:nth-child(even)) {
593
+ background: rgba(30, 41, 59, 0.5);
594
+ }
595
+ </style>