@jjlmoya/utils-health 1.1.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 (155) hide show
  1. package/package.json +60 -0
  2. package/src/category/i18n/en.ts +60 -0
  3. package/src/category/i18n/es.ts +60 -0
  4. package/src/category/i18n/fr.ts +60 -0
  5. package/src/category/index.ts +22 -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 +28 -0
  10. package/src/env.d.ts +5 -0
  11. package/src/index.ts +36 -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/faq_count.test.ts +19 -0
  17. package/src/tests/locale_completeness.test.ts +42 -0
  18. package/src/tests/mocks/astro_mock.js +2 -0
  19. package/src/tests/no_h1_in_components.test.ts +48 -0
  20. package/src/tests/schemas_fulfillment.test.ts +23 -0
  21. package/src/tests/seo_length.test.ts +22 -0
  22. package/src/tests/title_quality.test.ts +55 -0
  23. package/src/tests/tool_validation.test.ts +17 -0
  24. package/src/tool/binauralTuner/bibliography.astro +14 -0
  25. package/src/tool/binauralTuner/component.astro +687 -0
  26. package/src/tool/binauralTuner/i18n/en.ts +187 -0
  27. package/src/tool/binauralTuner/i18n/es.ts +187 -0
  28. package/src/tool/binauralTuner/i18n/fr.ts +187 -0
  29. package/src/tool/binauralTuner/index.ts +27 -0
  30. package/src/tool/binauralTuner/seo.astro +14 -0
  31. package/src/tool/binauralTuner/ui.ts +18 -0
  32. package/src/tool/bloodUnitConverter/bibliography.astro +14 -0
  33. package/src/tool/bloodUnitConverter/component.astro +915 -0
  34. package/src/tool/bloodUnitConverter/i18n/en.ts +227 -0
  35. package/src/tool/bloodUnitConverter/i18n/es.ts +250 -0
  36. package/src/tool/bloodUnitConverter/i18n/fr.ts +218 -0
  37. package/src/tool/bloodUnitConverter/index.ts +27 -0
  38. package/src/tool/bloodUnitConverter/seo.astro +14 -0
  39. package/src/tool/bloodUnitConverter/ui.ts +38 -0
  40. package/src/tool/bmiCalculator/bibliography.astro +14 -0
  41. package/src/tool/bmiCalculator/component.astro +415 -0
  42. package/src/tool/bmiCalculator/i18n/en.ts +217 -0
  43. package/src/tool/bmiCalculator/i18n/es.ts +221 -0
  44. package/src/tool/bmiCalculator/i18n/fr.ts +217 -0
  45. package/src/tool/bmiCalculator/index.ts +27 -0
  46. package/src/tool/bmiCalculator/seo.astro +14 -0
  47. package/src/tool/bmiCalculator/ui.ts +21 -0
  48. package/src/tool/breathingVisualizer/bibliography.astro +14 -0
  49. package/src/tool/breathingVisualizer/component.astro +636 -0
  50. package/src/tool/breathingVisualizer/i18n/en.ts +206 -0
  51. package/src/tool/breathingVisualizer/i18n/es.ts +206 -0
  52. package/src/tool/breathingVisualizer/i18n/fr.ts +206 -0
  53. package/src/tool/breathingVisualizer/index.ts +27 -0
  54. package/src/tool/breathingVisualizer/seo.astro +14 -0
  55. package/src/tool/breathingVisualizer/ui.ts +31 -0
  56. package/src/tool/caffeineTracker/bibliography.astro +14 -0
  57. package/src/tool/caffeineTracker/component.astro +1210 -0
  58. package/src/tool/caffeineTracker/i18n/en.ts +198 -0
  59. package/src/tool/caffeineTracker/i18n/es.ts +198 -0
  60. package/src/tool/caffeineTracker/i18n/fr.ts +198 -0
  61. package/src/tool/caffeineTracker/index.ts +27 -0
  62. package/src/tool/caffeineTracker/logic.ts +31 -0
  63. package/src/tool/caffeineTracker/seo.astro +14 -0
  64. package/src/tool/caffeineTracker/ui.ts +36 -0
  65. package/src/tool/daltonismSimulator/bibliography.astro +14 -0
  66. package/src/tool/daltonismSimulator/component.astro +383 -0
  67. package/src/tool/daltonismSimulator/i18n/en.ts +188 -0
  68. package/src/tool/daltonismSimulator/i18n/es.ts +218 -0
  69. package/src/tool/daltonismSimulator/i18n/fr.ts +168 -0
  70. package/src/tool/daltonismSimulator/index.ts +27 -0
  71. package/src/tool/daltonismSimulator/seo.astro +14 -0
  72. package/src/tool/daltonismSimulator/ui.ts +20 -0
  73. package/src/tool/digestionStopwatch/bibliography.astro +14 -0
  74. package/src/tool/digestionStopwatch/component.astro +627 -0
  75. package/src/tool/digestionStopwatch/i18n/en.ts +173 -0
  76. package/src/tool/digestionStopwatch/i18n/es.ts +173 -0
  77. package/src/tool/digestionStopwatch/i18n/fr.ts +173 -0
  78. package/src/tool/digestionStopwatch/index.ts +27 -0
  79. package/src/tool/digestionStopwatch/logic.ts +63 -0
  80. package/src/tool/digestionStopwatch/seo.astro +14 -0
  81. package/src/tool/digestionStopwatch/ui.ts +20 -0
  82. package/src/tool/epworthSleepinessScale/bibliography.astro +14 -0
  83. package/src/tool/epworthSleepinessScale/component.astro +528 -0
  84. package/src/tool/epworthSleepinessScale/i18n/en.ts +217 -0
  85. package/src/tool/epworthSleepinessScale/i18n/es.ts +217 -0
  86. package/src/tool/epworthSleepinessScale/i18n/fr.ts +217 -0
  87. package/src/tool/epworthSleepinessScale/index.ts +27 -0
  88. package/src/tool/epworthSleepinessScale/seo.astro +14 -0
  89. package/src/tool/epworthSleepinessScale/ui.ts +27 -0
  90. package/src/tool/hydrationCalculator/bibliography.astro +14 -0
  91. package/src/tool/hydrationCalculator/component.astro +694 -0
  92. package/src/tool/hydrationCalculator/i18n/en.ts +217 -0
  93. package/src/tool/hydrationCalculator/i18n/es.ts +222 -0
  94. package/src/tool/hydrationCalculator/i18n/fr.ts +199 -0
  95. package/src/tool/hydrationCalculator/index.ts +27 -0
  96. package/src/tool/hydrationCalculator/seo.astro +14 -0
  97. package/src/tool/hydrationCalculator/ui.ts +28 -0
  98. package/src/tool/pelliRobsonTest/bibliography.astro +14 -0
  99. package/src/tool/pelliRobsonTest/component.astro +653 -0
  100. package/src/tool/pelliRobsonTest/i18n/en.ts +205 -0
  101. package/src/tool/pelliRobsonTest/i18n/es.ts +205 -0
  102. package/src/tool/pelliRobsonTest/i18n/fr.ts +205 -0
  103. package/src/tool/pelliRobsonTest/index.ts +27 -0
  104. package/src/tool/pelliRobsonTest/seo.astro +14 -0
  105. package/src/tool/pelliRobsonTest/ui.ts +21 -0
  106. package/src/tool/peripheralVisionTrainer/bibliography.astro +14 -0
  107. package/src/tool/peripheralVisionTrainer/component.astro +678 -0
  108. package/src/tool/peripheralVisionTrainer/i18n/en.ts +224 -0
  109. package/src/tool/peripheralVisionTrainer/i18n/es.ts +224 -0
  110. package/src/tool/peripheralVisionTrainer/i18n/fr.ts +211 -0
  111. package/src/tool/peripheralVisionTrainer/index.ts +27 -0
  112. package/src/tool/peripheralVisionTrainer/seo.astro +14 -0
  113. package/src/tool/peripheralVisionTrainer/ui.ts +26 -0
  114. package/src/tool/readingDistanceCalculator/bibliography.astro +14 -0
  115. package/src/tool/readingDistanceCalculator/component.astro +588 -0
  116. package/src/tool/readingDistanceCalculator/i18n/en.ts +202 -0
  117. package/src/tool/readingDistanceCalculator/i18n/es.ts +215 -0
  118. package/src/tool/readingDistanceCalculator/i18n/fr.ts +193 -0
  119. package/src/tool/readingDistanceCalculator/index.ts +31 -0
  120. package/src/tool/readingDistanceCalculator/seo.astro +14 -0
  121. package/src/tool/readingDistanceCalculator/ui.ts +18 -0
  122. package/src/tool/screenDecompressionTime/bibliography.astro +14 -0
  123. package/src/tool/screenDecompressionTime/component.astro +671 -0
  124. package/src/tool/screenDecompressionTime/i18n/en.ts +225 -0
  125. package/src/tool/screenDecompressionTime/i18n/es.ts +247 -0
  126. package/src/tool/screenDecompressionTime/i18n/fr.ts +225 -0
  127. package/src/tool/screenDecompressionTime/index.ts +27 -0
  128. package/src/tool/screenDecompressionTime/seo.astro +14 -0
  129. package/src/tool/screenDecompressionTime/ui.ts +32 -0
  130. package/src/tool/tinnitusReliever/bibliography.astro +14 -0
  131. package/src/tool/tinnitusReliever/component.astro +581 -0
  132. package/src/tool/tinnitusReliever/i18n/en.ts +161 -0
  133. package/src/tool/tinnitusReliever/i18n/es.ts +161 -0
  134. package/src/tool/tinnitusReliever/i18n/fr.ts +161 -0
  135. package/src/tool/tinnitusReliever/index.ts +27 -0
  136. package/src/tool/tinnitusReliever/seo.astro +14 -0
  137. package/src/tool/tinnitusReliever/ui.ts +9 -0
  138. package/src/tool/ubeCalculator/bibliography.astro +14 -0
  139. package/src/tool/ubeCalculator/component.astro +683 -0
  140. package/src/tool/ubeCalculator/i18n/en.ts +200 -0
  141. package/src/tool/ubeCalculator/i18n/es.ts +200 -0
  142. package/src/tool/ubeCalculator/i18n/fr.ts +196 -0
  143. package/src/tool/ubeCalculator/index.ts +27 -0
  144. package/src/tool/ubeCalculator/seo.astro +14 -0
  145. package/src/tool/ubeCalculator/ui.ts +26 -0
  146. package/src/tool/waterPurifier/bibliography.astro +14 -0
  147. package/src/tool/waterPurifier/component.astro +628 -0
  148. package/src/tool/waterPurifier/i18n/en.ts +167 -0
  149. package/src/tool/waterPurifier/i18n/es.ts +167 -0
  150. package/src/tool/waterPurifier/i18n/fr.ts +167 -0
  151. package/src/tool/waterPurifier/index.ts +27 -0
  152. package/src/tool/waterPurifier/seo.astro +14 -0
  153. package/src/tool/waterPurifier/ui.ts +18 -0
  154. package/src/tools.ts +19 -0
  155. package/src/types.ts +72 -0
@@ -0,0 +1,528 @@
1
+ ---
2
+ import type { EpworthSleepinessScaleUI } from './ui';
3
+
4
+ interface Props {
5
+ ui?: Partial<EpworthSleepinessScaleUI>;
6
+ }
7
+
8
+ const ui = (Astro.props.ui ?? {}) as EpworthSleepinessScaleUI;
9
+ const STEPS = 8;
10
+ ---
11
+
12
+ <div class="ess" data-ui={JSON.stringify(ui)}>
13
+
14
+ <div class="ess__quiz" id="ess-quiz">
15
+ <div class="ess__progress">
16
+ <div class="ess__progress-fill" id="ess-progress"></div>
17
+ </div>
18
+
19
+ <div class="ess__cards" id="ess-cards">
20
+ {Array.from({ length: STEPS }).map((_, idx) => (
21
+ <div class={`ess__card${idx === 0 ? ' ess__card--active' : ''}`} data-step={idx}>
22
+ <div class="ess__question-header">
23
+ <span class="ess__question-number">
24
+ <span data-key="situationPrefix">Situación</span>
25
+ {' '}{idx + 1}{' '}
26
+ <span data-key="situationOf">de</span>
27
+ {' '}{STEPS}
28
+ </span>
29
+ <h3 class="ess__question-text" data-key={`sit${idx}`}></h3>
30
+ </div>
31
+
32
+ <div class="ess__options">
33
+ {[0, 1, 2, 3].map((val) => (
34
+ <button class="ess__option" data-value={val}>
35
+ <span class="ess__option-label" data-key={`opt${val}`}></span>
36
+ </button>
37
+ ))}
38
+ </div>
39
+ </div>
40
+ ))}
41
+ </div>
42
+
43
+ <div class="ess__nav">
44
+ <button class="ess__nav-btn" id="ess-prev" disabled>
45
+ ← <span data-key="btnPrev">Anterior</span>
46
+ </button>
47
+ <span class="ess__step-indicator" id="ess-indicator">1 / {STEPS}</span>
48
+ </div>
49
+ </div>
50
+
51
+
52
+ <div class="ess__results" id="ess-results">
53
+ <div class="ess__score-circle">
54
+ <span class="ess__score-num" id="ess-final">0</span>
55
+ <span class="ess__score-of" data-key="scoreOf">de 24</span>
56
+ </div>
57
+
58
+ <div class="ess__badge" id="ess-badge">Normal</div>
59
+ <p class="ess__result-desc" id="ess-desc"></p>
60
+
61
+ <button class="ess__reset-btn" id="ess-reset" data-key="btnReset">
62
+ Reiniciar Evaluación
63
+ </button>
64
+ </div>
65
+ </div>
66
+
67
+ <style>
68
+ .ess {
69
+ --ess-primary: #3b82f6;
70
+ --ess-accent: #f59e0b;
71
+ --ess-success: #10b981;
72
+ --ess-danger: #ef4444;
73
+ --ess-warning: #f97316;
74
+ --ess-bg: #f8fafc;
75
+ --ess-surface: #fff;
76
+ --ess-border: rgba(59, 130, 246, 0.2);
77
+ --ess-text: #0f172a;
78
+ --ess-muted: #475569;
79
+ --ess-option-bg: #f1f5f9;
80
+ --ess-option-border: rgba(0, 0, 0, 0.06);
81
+ --ess-nav-bg: #f1f5f9;
82
+ --ess-nav-border: #cbd5e1;
83
+ --ess-nav-text: #1e293b;
84
+ --ess-progress-track: rgba(0, 0, 0, 0.06);
85
+
86
+ max-width: 860px;
87
+ margin: 0 auto;
88
+ padding: 1rem;
89
+ }
90
+
91
+
92
+ .ess__quiz,
93
+ .ess__results {
94
+ background: var(--ess-surface);
95
+ border: 2px solid var(--ess-border);
96
+ border-radius: 2.5rem;
97
+ padding: 4rem;
98
+ position: relative;
99
+ overflow: hidden;
100
+ }
101
+
102
+
103
+ .ess__progress {
104
+ height: 8px;
105
+ background: var(--ess-progress-track);
106
+ border-radius: 10px;
107
+ overflow: hidden;
108
+ margin-bottom: 3rem;
109
+ border: 1px solid var(--ess-option-border);
110
+ }
111
+
112
+ .ess__progress-fill {
113
+ height: 100%;
114
+ background: linear-gradient(90deg, var(--ess-primary), var(--ess-success));
115
+ width: 0%;
116
+ transition: width 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
117
+ box-shadow: 0 0 12px rgba(59, 130, 246, 0.4);
118
+ }
119
+
120
+
121
+ .ess__card {
122
+ display: none;
123
+ animation: ess-slide-in 0.5s cubic-bezier(0.23, 1, 0.32, 1);
124
+ }
125
+
126
+ .ess__card--active {
127
+ display: block;
128
+ }
129
+
130
+ @keyframes ess-slide-in {
131
+ from { opacity: 0; transform: scale(0.97) translateY(16px); }
132
+ to { opacity: 1; transform: scale(1) translateY(0); }
133
+ }
134
+
135
+ .ess__question-header {
136
+ margin-bottom: 3rem;
137
+ text-align: center;
138
+ }
139
+
140
+ .ess__question-number {
141
+ font-size: 0.8rem;
142
+ text-transform: uppercase;
143
+ letter-spacing: 3px;
144
+ color: var(--ess-accent);
145
+ font-weight: 900;
146
+ margin-bottom: 1rem;
147
+ display: block;
148
+ }
149
+
150
+ .ess__question-text {
151
+ font-size: 2.2rem;
152
+ font-weight: 800;
153
+ line-height: 1.2;
154
+ color: var(--ess-text);
155
+ text-wrap: balance;
156
+ margin: 0;
157
+ }
158
+
159
+
160
+ .ess__options {
161
+ display: grid;
162
+ grid-template-columns: repeat(2, 1fr);
163
+ gap: 1.5rem;
164
+ }
165
+
166
+ .ess__option {
167
+ background: var(--ess-option-bg);
168
+ border: 1px solid var(--ess-option-border);
169
+ border-radius: 1.5rem;
170
+ padding: 1.75rem 1.5rem;
171
+ cursor: pointer;
172
+ transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
173
+ text-align: center;
174
+ display: flex;
175
+ justify-content: center;
176
+ align-items: center;
177
+ }
178
+
179
+ .ess__option:hover {
180
+ background: rgba(59, 130, 246, 0.08);
181
+ border-color: var(--ess-primary);
182
+ transform: translateY(-4px);
183
+ box-shadow: 0 8px 24px rgba(59, 130, 246, 0.12);
184
+ }
185
+
186
+ .ess :global(.ess__option--selected) {
187
+ background: var(--ess-primary);
188
+ border-color: var(--ess-primary);
189
+ color: #fff;
190
+ box-shadow: 0 8px 24px rgba(59, 130, 246, 0.35);
191
+ }
192
+
193
+ .ess :global(.ess__option--selected) .ess__option-label {
194
+ color: #fff;
195
+ }
196
+
197
+ .ess__option-label {
198
+ font-size: 1.2rem;
199
+ font-weight: 700;
200
+ color: var(--ess-text);
201
+ }
202
+
203
+
204
+ .ess__nav {
205
+ margin-top: 3.5rem;
206
+ display: flex;
207
+ justify-content: space-between;
208
+ align-items: center;
209
+ border-top: 1px solid var(--ess-option-border);
210
+ padding-top: 2rem;
211
+ }
212
+
213
+ .ess__nav-btn {
214
+ background: var(--ess-nav-bg);
215
+ border: 1px solid var(--ess-nav-border);
216
+ color: var(--ess-nav-text);
217
+ padding: 0.875rem 1.75rem;
218
+ border-radius: 1rem;
219
+ cursor: pointer;
220
+ font-weight: 700;
221
+ font-size: 1rem;
222
+ transition: all 0.2s ease;
223
+ display: flex;
224
+ align-items: center;
225
+ gap: 0.5rem;
226
+ }
227
+
228
+ .ess__nav-btn:hover:not(:disabled) {
229
+ background: var(--ess-primary);
230
+ border-color: var(--ess-primary);
231
+ color: #fff;
232
+ transform: scale(1.05);
233
+ }
234
+
235
+ .ess__nav-btn:disabled {
236
+ opacity: 0.25;
237
+ cursor: not-allowed;
238
+ }
239
+
240
+ .ess__step-indicator {
241
+ font-weight: 700;
242
+ opacity: 0.45;
243
+ color: var(--ess-text);
244
+ }
245
+
246
+
247
+ .ess__results {
248
+ display: none;
249
+ text-align: center;
250
+ animation: ess-result-reveal 0.7s cubic-bezier(0.19, 1, 0.22, 1);
251
+ }
252
+
253
+ .ess__results--visible {
254
+ display: block;
255
+ }
256
+
257
+ @keyframes ess-result-reveal {
258
+ from { opacity: 0; transform: translateY(24px); }
259
+ to { opacity: 1; transform: translateY(0); }
260
+ }
261
+
262
+ .ess__score-circle {
263
+ width: 220px;
264
+ height: 220px;
265
+ border-radius: 50%;
266
+ border: 10px solid var(--ess-border);
267
+ background: var(--ess-option-bg);
268
+ margin: 0 auto 2.5rem;
269
+ display: flex;
270
+ flex-direction: column;
271
+ justify-content: center;
272
+ align-items: center;
273
+ box-shadow: inset 0 0 30px rgba(59, 130, 246, 0.08);
274
+ }
275
+
276
+ .ess__score-num {
277
+ font-size: 5rem;
278
+ font-weight: 950;
279
+ line-height: 1;
280
+ background: linear-gradient(135deg, var(--ess-text) 0%, var(--ess-primary) 100%);
281
+ -webkit-background-clip: text;
282
+ background-clip: text;
283
+ -webkit-text-fill-color: transparent;
284
+ }
285
+
286
+ .ess__score-of {
287
+ font-size: 1.1rem;
288
+ color: var(--ess-muted);
289
+ font-weight: 700;
290
+ margin-top: 0.25rem;
291
+ }
292
+
293
+ .ess__badge {
294
+ display: inline-block;
295
+ padding: 0.625rem 2.5rem;
296
+ border-radius: 3rem;
297
+ font-weight: 900;
298
+ font-size: 1.15rem;
299
+ text-transform: uppercase;
300
+ letter-spacing: 2px;
301
+ margin-bottom: 1.5rem;
302
+ }
303
+
304
+ :global(.ess__badge--normal) { background: rgba(16, 185, 129, 0.12); color: #10b981; border: 2px solid #10b981; }
305
+ :global(.ess__badge--mild) { background: rgba(245, 158, 11, 0.12); color: #f59e0b; border: 2px solid #f59e0b; }
306
+ :global(.ess__badge--mod) { background: rgba(249, 115, 22, 0.12); color: #f97316; border: 2px solid #f97316; }
307
+ :global(.ess__badge--severe) { background: rgba(239, 68, 68, 0.12); color: #ef4444; border: 2px solid #ef4444; }
308
+
309
+ .ess__result-desc {
310
+ font-size: 1.2rem;
311
+ line-height: 1.7;
312
+ color: var(--ess-muted);
313
+ max-width: 620px;
314
+ margin: 0 auto 2.5rem;
315
+ }
316
+
317
+ .ess__reset-btn {
318
+ background: linear-gradient(135deg, var(--ess-primary) 0%, #1e40af 100%);
319
+ color: #fff;
320
+ border: none;
321
+ padding: 1.1rem 3rem;
322
+ border-radius: 1.5rem;
323
+ font-weight: 800;
324
+ font-size: 1.15rem;
325
+ cursor: pointer;
326
+ transition: all 0.3s ease;
327
+ box-shadow: 0 8px 24px rgba(59, 130, 246, 0.25);
328
+ }
329
+
330
+ .ess__reset-btn:hover {
331
+ transform: translateY(-3px) scale(1.02);
332
+ box-shadow: 0 20px 45px rgba(30, 64, 175, 0.4);
333
+ filter: brightness(1.1);
334
+ }
335
+
336
+
337
+ :global(.theme-dark) .ess {
338
+ --ess-bg: #0f172a;
339
+ --ess-surface: rgba(15, 23, 42, 0.85);
340
+ --ess-border: rgba(59, 130, 246, 0.3);
341
+ --ess-text: #f8fafc;
342
+ --ess-muted: #94a3b8;
343
+ --ess-option-bg: rgba(255, 255, 255, 0.04);
344
+ --ess-option-border: rgba(255, 255, 255, 0.08);
345
+ --ess-nav-bg: rgba(15, 23, 42, 0.5);
346
+ --ess-nav-border: rgba(59, 130, 246, 0.3);
347
+ --ess-nav-text: #f8fafc;
348
+ --ess-progress-track: rgba(255, 255, 255, 0.05);
349
+ }
350
+
351
+ :global(.theme-dark) .ess__quiz,
352
+ :global(.theme-dark) .ess__results {
353
+ backdrop-filter: blur(16px);
354
+ -webkit-backdrop-filter: blur(16px);
355
+ }
356
+
357
+ :global(.theme-dark) .ess__score-circle {
358
+ background: rgba(15, 23, 42, 0.5);
359
+ }
360
+
361
+ :global(.theme-dark) .ess__score-num {
362
+ background: linear-gradient(135deg, #fff 0%, var(--ess-primary) 100%);
363
+ -webkit-background-clip: text;
364
+ background-clip: text;
365
+ -webkit-text-fill-color: transparent;
366
+ }
367
+
368
+ :global(.theme-dark) .ess__option:hover {
369
+ background: rgba(59, 130, 246, 0.1);
370
+ }
371
+
372
+
373
+ @media (max-width: 768px) {
374
+ .ess__quiz,
375
+ .ess__results {
376
+ padding: 2rem 1.5rem;
377
+ border-radius: 1.75rem;
378
+ }
379
+
380
+ .ess__question-text {
381
+ font-size: 1.6rem;
382
+ }
383
+
384
+ .ess__options {
385
+ grid-template-columns: 1fr;
386
+ gap: 0.875rem;
387
+ }
388
+
389
+ .ess__option {
390
+ padding: 1.25rem;
391
+ }
392
+
393
+ .ess__score-circle {
394
+ width: 170px;
395
+ height: 170px;
396
+ border-width: 6px;
397
+ }
398
+
399
+ .ess__score-num {
400
+ font-size: 3.5rem;
401
+ }
402
+ }
403
+ </style>
404
+
405
+ <script>
406
+ interface EssUI {
407
+ sit0?: string; sit1?: string; sit2?: string; sit3?: string;
408
+ sit4?: string; sit5?: string; sit6?: string; sit7?: string;
409
+ opt0?: string; opt1?: string; opt2?: string; opt3?: string;
410
+ situationPrefix?: string; situationOf?: string;
411
+ btnPrev?: string;
412
+ scoreOf?: string;
413
+ badgeNormal?: string; descNormal?: string;
414
+ badgeMild?: string; descMild?: string;
415
+ badgeMod?: string; descMod?: string;
416
+ badgeSevere?: string; descSevere?: string;
417
+ btnReset?: string;
418
+ }
419
+
420
+ interface BadgeTier { badge: string; cls: string; desc: string; }
421
+
422
+ function applyUI(container: Element, ui: EssUI): void {
423
+ container.querySelectorAll<HTMLElement>('[data-key]').forEach((el) => {
424
+ const key = el.dataset.key as keyof EssUI;
425
+ const val = ui[key];
426
+ if (val) el.textContent = val;
427
+ });
428
+ }
429
+
430
+ // eslint-disable-next-line complexity
431
+ function getBadgeTier(total: number, ui: EssUI): BadgeTier {
432
+ const tiers: Array<[number, BadgeTier]> = [
433
+ [15, { badge: ui.badgeSevere ?? 'Grave', cls: 'ess__badge--severe', desc: ui.descSevere ?? '' }],
434
+ [12, { badge: ui.badgeMod ?? 'Moderada', cls: 'ess__badge--mod', desc: ui.descMod ?? '' }],
435
+ [10, { badge: ui.badgeMild ?? 'Leve', cls: 'ess__badge--mild', desc: ui.descMild ?? '' }],
436
+ ];
437
+ const tier = tiers.find(([threshold]) => total > threshold);
438
+ return tier?.[1] ?? { badge: ui.badgeNormal ?? 'Normal', cls: 'ess__badge--normal', desc: ui.descNormal ?? '' };
439
+ }
440
+
441
+ // eslint-disable-next-line max-lines-per-function
442
+ function initEss(container: Element): void {
443
+ const ui: EssUI = JSON.parse((container as HTMLElement).dataset.ui ?? '{}');
444
+ applyUI(container, ui);
445
+
446
+ const quizEl = container.querySelector<HTMLElement>('#ess-quiz');
447
+ const resultsEl = container.querySelector<HTMLElement>('#ess-results');
448
+ const progressEl = container.querySelector<HTMLElement>('#ess-progress');
449
+ const indicatorEl = container.querySelector<HTMLElement>('#ess-indicator');
450
+ const prevBtn = container.querySelector<HTMLButtonElement>('#ess-prev');
451
+ const finalEl = container.querySelector<HTMLElement>('#ess-final');
452
+ const badgeEl = container.querySelector<HTMLElement>('#ess-badge');
453
+ const descEl = container.querySelector<HTMLElement>('#ess-desc');
454
+ const cards = container.querySelectorAll<HTMLElement>('.ess__card');
455
+
456
+ const TOTAL = cards.length;
457
+ let currentStep = 0;
458
+ const scores: number[] = new Array(TOTAL).fill(-1);
459
+
460
+ function updateUI(): void {
461
+ cards.forEach((card, idx) => card.classList.toggle('ess__card--active', idx === currentStep));
462
+ const pct = (currentStep / TOTAL) * 100;
463
+ if (progressEl) progressEl.style.width = `${pct}%`;
464
+ if (indicatorEl) indicatorEl.textContent = `${currentStep + 1} / ${TOTAL}`;
465
+ if (prevBtn) prevBtn.disabled = currentStep === 0;
466
+
467
+ const card = cards[currentStep];
468
+ card?.querySelectorAll<HTMLElement>('.ess__option').forEach((btn) => {
469
+ const val = parseInt(btn.dataset.value ?? '0');
470
+ btn.classList.toggle('ess__option--selected', scores[currentStep] === val);
471
+ });
472
+ }
473
+
474
+ function handleOption(value: number): void {
475
+ scores[currentStep] = value;
476
+ if (currentStep < TOTAL - 1) {
477
+ currentStep++;
478
+ setTimeout(updateUI, 180);
479
+ } else {
480
+ showResults();
481
+ }
482
+ }
483
+
484
+ function showResults(): void {
485
+ const total = scores.reduce((a, b) => a + (b >= 0 ? b : 0), 0);
486
+ if (quizEl) quizEl.style.display = 'none';
487
+ if (resultsEl) {
488
+ resultsEl.style.display = 'block';
489
+ resultsEl.classList.add('ess__results--visible');
490
+ }
491
+ if (finalEl) finalEl.textContent = total.toString();
492
+ if (badgeEl && descEl) {
493
+ const tier = getBadgeTier(total, ui);
494
+ badgeEl.textContent = tier.badge;
495
+ badgeEl.className = `ess__badge ${tier.cls}`;
496
+ descEl.textContent = tier.desc;
497
+ }
498
+ }
499
+
500
+ function reset(): void {
501
+ currentStep = 0;
502
+ scores.fill(-1);
503
+ if (quizEl) quizEl.style.display = 'block';
504
+ if (resultsEl) {
505
+ resultsEl.style.display = 'none';
506
+ resultsEl.classList.remove('ess__results--visible');
507
+ }
508
+ updateUI();
509
+ }
510
+
511
+ container.querySelectorAll<HTMLElement>('.ess__option').forEach((btn) => {
512
+ btn.addEventListener('click', () => {
513
+ const val = parseInt(btn.dataset.value ?? '0');
514
+ handleOption(val);
515
+ });
516
+ });
517
+
518
+ prevBtn?.addEventListener('click', () => {
519
+ if (currentStep > 0) { currentStep--; updateUI(); }
520
+ });
521
+
522
+ container.querySelector('#ess-reset')?.addEventListener('click', reset);
523
+
524
+ updateUI();
525
+ }
526
+
527
+ document.querySelectorAll<HTMLElement>('.ess').forEach(initEss);
528
+ </script>