@golstats/gsc-timeline-reports 1.0.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 (96) hide show
  1. package/README.md +2 -0
  2. package/dist/css/fonts.css +91 -0
  3. package/dist/fonts/BebasNeue-Bold.otf +0 -0
  4. package/dist/fonts/BebasNeue-Bold.ttf +0 -0
  5. package/dist/fonts/BebasNeue-Bold.woff2 +0 -0
  6. package/dist/fonts/BebasNeue-Book.otf +0 -0
  7. package/dist/fonts/BebasNeue-Book.ttf +0 -0
  8. package/dist/fonts/BebasNeue-Book.woff2 +0 -0
  9. package/dist/fonts/BebasNeue-Light.otf +0 -0
  10. package/dist/fonts/BebasNeue-Light.ttf +0 -0
  11. package/dist/fonts/BebasNeue-Light.woff2 +0 -0
  12. package/dist/fonts/BebasNeue-Regular.otf +0 -0
  13. package/dist/fonts/BebasNeue-Regular.ttf +0 -0
  14. package/dist/fonts/BebasNeue-Regular.woff2 +0 -0
  15. package/dist/fonts/BebasNeue-Thin.otf +0 -0
  16. package/dist/fonts/BebasNeue-Thin.ttf +0 -0
  17. package/dist/fonts/BebasNeue-Thin.woff2 +0 -0
  18. package/dist/fonts/Montserrat-Black.otf +0 -0
  19. package/dist/fonts/Montserrat-BlackItalic.otf +0 -0
  20. package/dist/fonts/Montserrat-Bold.otf +0 -0
  21. package/dist/fonts/Montserrat-BoldItalic.otf +0 -0
  22. package/dist/fonts/Montserrat-ExtraBold.otf +0 -0
  23. package/dist/fonts/Montserrat-ExtraBoldItalic.otf +0 -0
  24. package/dist/fonts/Montserrat-ExtraLight.otf +0 -0
  25. package/dist/fonts/Montserrat-ExtraLightItalic.otf +0 -0
  26. package/dist/fonts/Montserrat-Italic.otf +0 -0
  27. package/dist/fonts/Montserrat-Light.otf +0 -0
  28. package/dist/fonts/Montserrat-LightItalic.otf +0 -0
  29. package/dist/fonts/Montserrat-Medium.otf +0 -0
  30. package/dist/fonts/Montserrat-MediumItalic.otf +0 -0
  31. package/dist/fonts/Montserrat-Regular.otf +0 -0
  32. package/dist/fonts/Montserrat-SemiBold.otf +0 -0
  33. package/dist/fonts/Montserrat-SemiBoldItalic.otf +0 -0
  34. package/dist/fonts/Montserrat-Thin.otf +0 -0
  35. package/dist/fonts/Montserrat-ThinItalic.otf +0 -0
  36. package/dist/fonts/Oswald-Bold.ttf +0 -0
  37. package/dist/fonts/Oswald-ExtraLight.ttf +0 -0
  38. package/dist/fonts/Oswald-Light.ttf +0 -0
  39. package/dist/fonts/Oswald-Medium.ttf +0 -0
  40. package/dist/fonts/Oswald-Regular.ttf +0 -0
  41. package/dist/fonts/Oswald-SemiBold.ttf +0 -0
  42. package/dist/fonts/Poppins-Black.otf +0 -0
  43. package/dist/fonts/Poppins-BlackItalic.otf +0 -0
  44. package/dist/fonts/Poppins-Bold.otf +0 -0
  45. package/dist/fonts/Poppins-BoldItalic.otf +0 -0
  46. package/dist/fonts/Poppins-ExtraBold.otf +0 -0
  47. package/dist/fonts/Poppins-ExtraBoldItalic.otf +0 -0
  48. package/dist/fonts/Poppins-ExtraLight.otf +0 -0
  49. package/dist/fonts/Poppins-ExtraLightItalic.otf +0 -0
  50. package/dist/fonts/Poppins-Italic.otf +0 -0
  51. package/dist/fonts/Poppins-Light.otf +0 -0
  52. package/dist/fonts/Poppins-LightItalic.otf +0 -0
  53. package/dist/fonts/Poppins-Medium.otf +0 -0
  54. package/dist/fonts/Poppins-MediumItalic.otf +0 -0
  55. package/dist/fonts/Poppins-Regular.otf +0 -0
  56. package/dist/fonts/Poppins-SemiBold.otf +0 -0
  57. package/dist/fonts/Poppins-SemiBoldItalic.otf +0 -0
  58. package/dist/fonts/Poppins-Thin.otf +0 -0
  59. package/dist/fonts/Poppins-ThinItalic.otf +0 -0
  60. package/dist/gsc-timeline-reports.css +1 -0
  61. package/dist/gsc-timeline-reports.es.js +2513 -0
  62. package/dist/gsc-timeline-reports.umd.js +6 -0
  63. package/dist/images/cancha-horizontal-raw.jpg +0 -0
  64. package/dist/images/cancha-horizontal.jpg +0 -0
  65. package/dist/images/canchaRPH.svg +30 -0
  66. package/dist/images/events/atajada.svg +57 -0
  67. package/dist/images/events/cambio.svg +27 -0
  68. package/dist/images/events/falta.svg +43 -0
  69. package/dist/images/events/favicon.ico +0 -0
  70. package/dist/images/events/fin-del-partido.svg +44 -0
  71. package/dist/images/events/fuera-de-lugar.svg +58 -0
  72. package/dist/images/events/generic.svg +1 -0
  73. package/dist/images/events/gol.svg +49 -0
  74. package/dist/images/events/icn-cambio.svg +6 -0
  75. package/dist/images/events/icn-falta.svg +4 -0
  76. package/dist/images/events/icn-play.svg +3 -0
  77. package/dist/images/events/icn-tarjeta-amarilla.svg +3 -0
  78. package/dist/images/events/icn-tarjeta-roja.svg +3 -0
  79. package/dist/images/events/icn-tiro-a-porteria.svg +36 -0
  80. package/dist/images/events/icn-tiros-de-esquina.svg +18 -0
  81. package/dist/images/events/inicia-el-partido.svg +46 -0
  82. package/dist/images/events/jugada-peligrosa.svg +91 -0
  83. package/dist/images/events/penal-fallado.svg +195 -0
  84. package/dist/images/events/penal-marcado.svg +190 -0
  85. package/dist/images/events/tiempo-agregado.svg +75 -0
  86. package/dist/images/events/tiro-a-porteria.svg +81 -0
  87. package/dist/images/events/tiro-de-esquina.svg +55 -0
  88. package/dist/images/events/var.png +0 -0
  89. package/dist/images/events/var.svg +31 -0
  90. package/package.json +65 -0
  91. package/src/App.vue +60 -0
  92. package/src/components/gsc-timeline-reports.vue +83 -0
  93. package/src/components/gsc-timeline.vue +3133 -0
  94. package/src/index.js +4 -0
  95. package/src/main.js +4 -0
  96. package/src/types.d.ts +45 -0
@@ -0,0 +1,3133 @@
1
+ <script setup>
2
+ import { ref, onBeforeUnmount, watch, onMounted, nextTick } from 'vue'
3
+ import axios from 'axios'
4
+
5
+ // Estado para el rango de minutos seleccionados
6
+ const minStart = ref(0) // Minuto inicial del rango
7
+ const minEnd = ref(96) // Minuto final del rango
8
+ const startTime = ref('1') // Selector de tiempo inicial (1 = primer tiempo, 2 = segundo tiempo)
9
+ const endTime = ref('2') // Selector de tiempo final
10
+ const firstHalfEndMinute = ref(0) // Se actualizará con el valor del endpoint
11
+ const secondHalfStartMinute = ref(45) // Minuto de inicio del segundo tiempo
12
+ const secondHalfEndMinute = ref(96) // Minuto de finalización del segundo tiempo
13
+
14
+ // Variables para forzar la actualización de la vista
15
+ const leftHandlePosition = ref(0)
16
+ const rightHandlePosition = ref(0)
17
+ const rangeWidth = ref('0px')
18
+
19
+ // Array que representa todos los minutos del partido
20
+ const timelineMinutes = ref([])
21
+
22
+ // Emitir eventos
23
+ const emit = defineEmits(['range-change'])
24
+
25
+ // Definir las props
26
+ const props = defineProps({
27
+ timelineWidth: {
28
+ type: Number,
29
+ required: true,
30
+ default: 1010,
31
+ },
32
+ gameId: {
33
+ type: Number,
34
+ required: true,
35
+ },
36
+ homeTeam: {
37
+ type: Number,
38
+ required: true,
39
+ },
40
+ isDefault: {
41
+ type: Boolean,
42
+ required: false,
43
+ },
44
+ awayTeam: {
45
+ type: Number,
46
+ required: true,
47
+ },
48
+ token: {
49
+ type: String,
50
+ required: true,
51
+ },
52
+ })
53
+
54
+ // Crear instancia de axios con la configuración del token
55
+ const axiosInstance = axios.create({
56
+ headers: {
57
+ Authorization: `${props.token}`,
58
+ },
59
+ })
60
+
61
+ // Lista de eventos (se actualizará con los datos del partido)
62
+ const events = ref([])
63
+
64
+ // Variables para el arrastre
65
+ let dragging = null // Puede ser 'left', 'right' o null
66
+ const timelineRef = ref(null) // Referencia al elemento timeline
67
+ const isDragging = ref(false) // Estado para el arrastre
68
+ const containerWidth = ref(0)
69
+ const initialWidth = ref(0)
70
+ const hasScrollLeft = ref(false)
71
+ const hasScrollRight = ref(false)
72
+ let isActuallyDragging = false // Para detectar si realmente se está arrastrando
73
+ let dragStartX = 0 // Posición inicial del drag
74
+ const initialHandleIndex = ref(0) // Índice inicial del handle que se está arrastrando
75
+
76
+ // Variables de control para distinguir cambios manuales vs automáticos
77
+ const isManualTimeChange = ref(false)
78
+ const isIncrementing = ref(false) // Nueva variable para controlar operaciones de incremento/decremento
79
+
80
+ // Número total de minutos en el timeline
81
+ const minTotal = ref(96)
82
+
83
+ // Referencia para el contenedor de scroll
84
+ const scrollContainer = ref(null)
85
+
86
+ // --- NUEVO: Datos dummy para modo default ---
87
+ const dummyEvents = [
88
+ {
89
+ minute: 1,
90
+ match_lapse: 1,
91
+ event: [
92
+ {
93
+ minute: 1,
94
+ minuteLabel: 'E',
95
+ icon: 'icon-goal',
96
+ team: 'local',
97
+ match_lapse: 1,
98
+ },
99
+ ],
100
+ },
101
+ {
102
+ minute: 10,
103
+ match_lapse: 1,
104
+ event: [
105
+ {
106
+ minute: 10,
107
+ minuteLabel: 'E',
108
+ icon: 'icon-red-card',
109
+ team: 'visitante',
110
+ match_lapse: 1,
111
+ },
112
+ ],
113
+ },
114
+ {
115
+ minute: 45,
116
+ match_lapse: 1,
117
+ event: [
118
+ {
119
+ minute: 45,
120
+ minuteLabel: 'E',
121
+ icon: 'icon-change',
122
+ team: 'local',
123
+ match_lapse: 1,
124
+ },
125
+ ],
126
+ },
127
+ {
128
+ minute: 55,
129
+ match_lapse: 2,
130
+ event: [
131
+ {
132
+ minute: 55,
133
+ minuteLabel: 'E',
134
+ icon: 'icon-goal',
135
+ team: 'visitante',
136
+ match_lapse: 2,
137
+ },
138
+ ],
139
+ },
140
+ {
141
+ minute: 90,
142
+ match_lapse: 2,
143
+ event: [
144
+ {
145
+ minute: 80,
146
+ minuteLabel: 'E',
147
+ icon: 'icon-goal',
148
+ team: 'local',
149
+ match_lapse: 2,
150
+ },
151
+ ],
152
+ },
153
+ ]
154
+
155
+ // Función para verificar si hay scroll
156
+ function checkScroll() {
157
+ if (scrollContainer.value) {
158
+ const container = scrollContainer.value
159
+ const maxScroll = container.scrollWidth - container.clientWidth
160
+ const currentScroll = container.scrollLeft
161
+
162
+ // Solo mostrar scroll si el contenido es más grande que el contenedor
163
+ const hasScroll = container.scrollWidth > container.clientWidth
164
+
165
+ // Actualizar estados de scroll
166
+ hasScrollLeft.value = hasScroll && currentScroll > 0
167
+ hasScrollRight.value = hasScroll && Math.ceil(currentScroll) < Math.floor(maxScroll)
168
+ }
169
+ }
170
+
171
+ // Función para actualizar el ancho del contenedor
172
+ function updateContainerWidth() {
173
+ if (timelineRef.value) {
174
+ const parentWidth = timelineRef.value.parentElement.clientWidth
175
+ containerWidth.value = parentWidth
176
+ // Solo establecemos el ancho inicial una vez
177
+ if (initialWidth.value === 0) {
178
+ initialWidth.value = parentWidth - 90
179
+ }
180
+ // Verificar scroll después de actualizar el ancho
181
+ nextTick(() => {
182
+ checkScroll()
183
+ })
184
+ }
185
+ }
186
+
187
+ // Función para calcular el minuto máximo
188
+ function calculateMaxMinute() {
189
+ if (events.value.length > 0) {
190
+ const maxEventMinute = Math.max(...events.value.map((event) => event.minute))
191
+ minTotal.value = maxEventMinute // Usar el minuto del último evento sin margen adicional
192
+ // Actualizar el rango seleccionado al minuto final
193
+ minEnd.value = minTotal.value
194
+ }
195
+ }
196
+
197
+ // Función para obtener los datos del partido
198
+ async function fetchGameData() {
199
+ if (props.isDefault) {
200
+ // Si es default, usar los eventos dummy
201
+ timelineMinutes.value = dummyEvents
202
+ events.value = dummyEvents.map((minute) => minute.event)
203
+ // Ajustar valores para los handlers y el rango
204
+ minStart.value = dummyEvents[0].minute
205
+ minEnd.value = dummyEvents[dummyEvents.length - 1].minute
206
+ startTime.value = dummyEvents[0].match_lapse.toString()
207
+ endTime.value = dummyEvents[dummyEvents.length - 1].match_lapse.toString()
208
+ leftHandlePosition.value = 0
209
+ rightHandlePosition.value = dummyEvents.length - 1
210
+ secondHalfEndMinute.value = dummyEvents[dummyEvents.length - 1].minute
211
+ minTotal.value = dummyEvents[dummyEvents.length - 1].minute
212
+ updateRangeWidth()
213
+ return
214
+ }
215
+ try {
216
+ const response = await axiosInstance.get(
217
+ `https://al2nv2dmkc.execute-api.us-west-2.amazonaws.com/prod/mxm/${props.gameId}`,
218
+ )
219
+
220
+ // Procesar los datos y crear el array de eventos
221
+ if (response.data && response.data.plays) {
222
+ // Encontrar el evento de fin del primer tiempo
223
+ const halfTimeEvent = response.data.plays.find(
224
+ (event) =>
225
+ event.event_type_id === 6 &&
226
+ event.comments?.includes('El árbitro silba el Final del Primer Tiempo'),
227
+ )
228
+
229
+ // Establecer el minuto de finalización del primer tiempo
230
+ if (halfTimeEvent) {
231
+ firstHalfEndMinute.value = halfTimeEvent.minute
232
+ }
233
+
234
+ // Calcular el minuto máximo usando todos los eventos
235
+ const maxEventMinute = Math.max(...response.data.plays.map((event) => event.minute))
236
+ secondHalfEndMinute.value = maxEventMinute
237
+ minTotal.value = maxEventMinute
238
+ minEnd.value = minTotal.value
239
+
240
+ // Crear el array de minutos del timeline
241
+ timelineMinutes.value = []
242
+
243
+ // Llenar el primer tiempo (todos los minutos)
244
+ for (let i = 0; i <= firstHalfEndMinute.value; i++) {
245
+ const eventsFound = response.data.plays.filter(
246
+ (e) =>
247
+ e.minute === i &&
248
+ e.match_lapse === 1 &&
249
+ (e.category_id === 9 ||
250
+ e.category_id === 3 ||
251
+ e.event_type_id === 1 ||
252
+ e.category_id === 10 ||
253
+ e.category_id === 13 ||
254
+ (e.event_type_id === 6 &&
255
+ e.comments?.includes('El árbitro silba el Final del Primer Tiempo'))),
256
+ )
257
+ const events = []
258
+ eventsFound.forEach((event) => {
259
+ events.push({
260
+ minute: event.minute,
261
+ minuteLabel: event.event_type_id === 6 ? 'MT' : event.minute.toString(),
262
+ icon: getEventIcon(event.event_type_id === 1 ? event.event_type_id : event.category_id),
263
+ team:
264
+ event.team_id === props.homeTeam
265
+ ? event.category_id === 13
266
+ ? 'visitante'
267
+ : 'local'
268
+ : event.category_id === 13
269
+ ? 'local'
270
+ : 'visitante',
271
+ match_lapse: event.match_lapse,
272
+ })
273
+ })
274
+
275
+ timelineMinutes.value.push({
276
+ minute: i,
277
+ match_lapse: 1,
278
+ event: events.length > 0 ? events : null,
279
+ })
280
+ }
281
+
282
+ // Llenar el segundo tiempo (todos los minutos)
283
+ for (let i = secondHalfStartMinute.value; i <= secondHalfEndMinute.value; i++) {
284
+ const eventsFound = response.data.plays.filter(
285
+ (e) =>
286
+ e.minute === i &&
287
+ e.match_lapse === 2 &&
288
+ (e.category_id === 9 ||
289
+ e.category_id === 3 ||
290
+ e.event_type_id === 1 ||
291
+ e.category_id === 10 ||
292
+ e.category_id === 13),
293
+ )
294
+ const events = []
295
+ eventsFound.forEach((event) => {
296
+ events.push({
297
+ minute: event.minute,
298
+ minuteLabel: event.event_type_id === 6 ? 'MT' : event.minute.toString(),
299
+ icon: getEventIcon(event.event_type_id === 1 ? event.event_type_id : event.category_id),
300
+ team:
301
+ event.team_id === props.homeTeam
302
+ ? event.category_id === 13
303
+ ? 'visitante'
304
+ : 'local'
305
+ : event.category_id === 13
306
+ ? 'local'
307
+ : 'visitante',
308
+ match_lapse: event.match_lapse,
309
+ })
310
+ })
311
+
312
+ timelineMinutes.value.push({
313
+ minute: i,
314
+ match_lapse: 2,
315
+ event: events.length > 0 ? events : null,
316
+ })
317
+ }
318
+
319
+ // Actualizar el array de eventos para mantener compatibilidad
320
+ events.value = timelineMinutes.value
321
+ .filter((minute) => minute.event !== null)
322
+ .map((minute) => minute.event)
323
+
324
+ // Establecer valores iniciales correctos para los handlers
325
+ if (timelineMinutes.value.length > 0) {
326
+ // Handler izquierdo: primer tiempo, primer minuto
327
+ const firstHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 1)
328
+ if (firstHalfMinutes.length > 0) {
329
+ const firstMinute = firstHalfMinutes[0]
330
+ minStart.value = firstMinute.minute
331
+ startTime.value = '1'
332
+ leftHandlePosition.value = timelineMinutes.value.findIndex(
333
+ (m) => m.minute === firstMinute.minute && m.match_lapse === 1,
334
+ )
335
+ }
336
+
337
+ // Handler derecho: segundo tiempo, último minuto
338
+ const secondHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 2)
339
+ if (secondHalfMinutes.length > 0) {
340
+ const lastMinute = secondHalfMinutes[secondHalfMinutes.length - 1]
341
+ minEnd.value = lastMinute.minute
342
+ endTime.value = '2'
343
+ rightHandlePosition.value = timelineMinutes.value.findIndex(
344
+ (m) => m.minute === lastMinute.minute && m.match_lapse === 2,
345
+ )
346
+ }
347
+
348
+ // Calcular el ancho inicial del rango
349
+ const startIndex = timelineMinutes.value.findIndex(
350
+ (m) => m.minute === minStart.value && m.match_lapse === parseInt(startTime.value),
351
+ )
352
+ const endIndex = timelineMinutes.value.findIndex(
353
+ (m) => m.minute === minEnd.value && m.match_lapse === parseInt(endTime.value),
354
+ )
355
+
356
+ if (startIndex !== -1 && endIndex !== -1 && startIndex < endIndex) {
357
+ const totalPositions = timelineMinutes.value.length
358
+ const startPos = (startIndex / (totalPositions - 1)) * (props.timelineWidth - 40)
359
+ const endPos = (endIndex / (totalPositions - 1)) * (props.timelineWidth - 40)
360
+ rangeWidth.value = `${endPos - startPos}px`
361
+ }
362
+ }
363
+ }
364
+ } catch (error) {
365
+ console.error('Error al obtener los datos del partido:', error)
366
+ }
367
+ }
368
+
369
+ // Función para determinar el icono según el tipo de evento
370
+ function getEventIcon(eventTypeId) {
371
+ const iconMap = {
372
+ 3: 'icon-goal',
373
+ 1: 'icon-goal',
374
+ 13: 'icon-goal',
375
+ 10: 'icon-change',
376
+ 9: 'icon-red-card',
377
+ // Agregar más mapeos según sea necesario
378
+ }
379
+ return iconMap[eventTypeId] || '' // Por defecto retorna icon-goal
380
+ }
381
+
382
+ // Observar cambios en el tamaño de la ventana
383
+ onMounted(() => {
384
+ calculateMaxMinute()
385
+ updateContainerWidth()
386
+ fetchGameData()
387
+
388
+ // Verificar scroll después de que los datos se hayan cargado
389
+ nextTick(() => {
390
+ checkScroll()
391
+ })
392
+
393
+ window.addEventListener('resize', () => {
394
+ updateContainerWidth()
395
+ })
396
+ })
397
+
398
+ onBeforeUnmount(() => {
399
+ window.removeEventListener('resize', checkScroll)
400
+ })
401
+
402
+ // Observar cambios en los eventos para actualizar el scroll
403
+ watch(
404
+ events,
405
+ () => {
406
+ nextTick(() => {
407
+ checkScroll()
408
+ })
409
+ },
410
+ { deep: true },
411
+ )
412
+
413
+ // Observar cambios en los valores
414
+ watch(
415
+ [minStart, minEnd, startTime, endTime],
416
+ () => {
417
+ // Solo emitir los valores, sin validación automática
418
+ handleRangeChange()
419
+ },
420
+ { immediate: true },
421
+ )
422
+
423
+ // Observar cambios en los selectores de tiempo para actualizar los minutos automáticamente
424
+ watch(
425
+ [startTime],
426
+ () => {
427
+ // No ejecutar si estamos incrementando/decrementando o arrastrando
428
+ if (isIncrementing.value || isDragging.value) return
429
+
430
+ // Validar que el tiempo inicial no sea mayor que el tiempo final
431
+ if (parseInt(startTime.value) > parseInt(endTime.value)) {
432
+ // Si el tiempo inicial es mayor que el final, ajustar el tiempo final
433
+ endTime.value = startTime.value
434
+ isManualTimeChange.value = true
435
+ }
436
+
437
+ // Solo aplicar cambios automáticos si no es un cambio manual
438
+ if (!isManualTimeChange.value) {
439
+ if (startTime.value === '1') {
440
+ // Primer tiempo: ir al primer minuto del primer tiempo
441
+ const firstHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 1)
442
+ if (firstHalfMinutes.length > 0) {
443
+ const firstMinute = firstHalfMinutes[0]
444
+ minStart.value = firstMinute.minute
445
+
446
+ // Actualizar la posición del handler izquierdo
447
+ const startIndex = timelineMinutes.value.findIndex(
448
+ (m) => m.minute === firstMinute.minute && m.match_lapse === 1,
449
+ )
450
+ if (startIndex !== -1) {
451
+ leftHandlePosition.value = startIndex
452
+ }
453
+ }
454
+ } else if (startTime.value === '2') {
455
+ // Segundo tiempo: ir al primer minuto del segundo tiempo
456
+ const secondHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 2)
457
+ if (secondHalfMinutes.length > 0) {
458
+ const firstMinute = secondHalfMinutes[0]
459
+ minStart.value = firstMinute.minute
460
+
461
+ // Actualizar la posición del handler izquierdo
462
+ const startIndex = timelineMinutes.value.findIndex(
463
+ (m) => m.minute === firstMinute.minute && m.match_lapse === 2,
464
+ )
465
+ if (startIndex !== -1) {
466
+ leftHandlePosition.value = startIndex
467
+ }
468
+ }
469
+ }
470
+ } else {
471
+ // Es un cambio manual, verificar si el minuto actual es válido
472
+ if (startTime.value === '1') {
473
+ const firstHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 1)
474
+ if (firstHalfMinutes.length > 0) {
475
+ const firstMinute = firstHalfMinutes[0]
476
+ const lastMinute = firstHalfMinutes[firstHalfMinutes.length - 1]
477
+
478
+ // Solo cambiar si el minuto actual no es válido para el primer tiempo
479
+ if (minStart.value < firstMinute.minute || minStart.value > lastMinute.minute) {
480
+ minStart.value = firstMinute.minute
481
+ }
482
+
483
+ // Actualizar la posición del handler izquierdo
484
+ const startIndex = timelineMinutes.value.findIndex(
485
+ (m) => m.minute === minStart.value && m.match_lapse === 1,
486
+ )
487
+ if (startIndex !== -1) {
488
+ leftHandlePosition.value = startIndex
489
+ }
490
+ }
491
+ } else if (startTime.value === '2') {
492
+ const secondHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 2)
493
+ if (secondHalfMinutes.length > 0) {
494
+ const firstMinute = secondHalfMinutes[0]
495
+ const lastMinute = secondHalfMinutes[secondHalfMinutes.length - 1]
496
+
497
+ // Solo cambiar si el minuto actual no es válido para el segundo tiempo
498
+ if (minStart.value < firstMinute.minute || minStart.value > lastMinute.minute) {
499
+ minStart.value = firstMinute.minute
500
+ }
501
+
502
+ // Actualizar la posición del handler izquierdo
503
+ const startIndex = timelineMinutes.value.findIndex(
504
+ (m) => m.minute === minStart.value && m.match_lapse === 2,
505
+ )
506
+ if (startIndex !== -1) {
507
+ leftHandlePosition.value = startIndex
508
+ }
509
+ }
510
+ }
511
+ }
512
+
513
+ // Resetear la bandera
514
+ isManualTimeChange.value = false
515
+
516
+ // Actualizar el ancho del rango
517
+ updateRangeWidth()
518
+ },
519
+ { immediate: true },
520
+ )
521
+
522
+ watch(
523
+ [endTime],
524
+ () => {
525
+ // No ejecutar si estamos incrementando/decrementando o arrastrando
526
+ if (isIncrementing.value || isDragging.value) return
527
+
528
+ // Validar que el tiempo final no sea menor que el tiempo inicial
529
+ if (parseInt(endTime.value) < parseInt(startTime.value)) {
530
+ // Si el tiempo final es menor que el inicial, ajustar el tiempo inicial
531
+ startTime.value = endTime.value
532
+ isManualTimeChange.value = true
533
+ }
534
+
535
+ // Solo aplicar cambios automáticos si no es un cambio manual
536
+ if (!isManualTimeChange.value) {
537
+ if (endTime.value === '1') {
538
+ // Primer tiempo: ir al último minuto del primer tiempo
539
+ const firstHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 1)
540
+ if (firstHalfMinutes.length > 0) {
541
+ const lastMinute = firstHalfMinutes[firstHalfMinutes.length - 1]
542
+ minEnd.value = lastMinute.minute
543
+
544
+ // Actualizar la posición del handler derecho
545
+ const endIndex = timelineMinutes.value.findIndex(
546
+ (m) => m.minute === lastMinute.minute && m.match_lapse === 1,
547
+ )
548
+ if (endIndex !== -1) {
549
+ rightHandlePosition.value = endIndex
550
+ }
551
+ }
552
+ } else if (endTime.value === '2') {
553
+ // Segundo tiempo: ir al último minuto del segundo tiempo
554
+ const secondHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 2)
555
+ if (secondHalfMinutes.length > 0) {
556
+ const lastMinute = secondHalfMinutes[secondHalfMinutes.length - 1]
557
+ minEnd.value = lastMinute.minute
558
+
559
+ // Actualizar la posición del handler derecho
560
+ const endIndex = timelineMinutes.value.findIndex(
561
+ (m) => m.minute === lastMinute.minute && m.match_lapse === 2,
562
+ )
563
+ if (endIndex !== -1) {
564
+ rightHandlePosition.value = endIndex
565
+ }
566
+ }
567
+ }
568
+ } else {
569
+ // Es un cambio manual, verificar si el minuto actual es válido
570
+ if (endTime.value === '1') {
571
+ const firstHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 1)
572
+ if (firstHalfMinutes.length > 0) {
573
+ const firstMinute = firstHalfMinutes[0]
574
+ const lastMinute = firstHalfMinutes[firstHalfMinutes.length - 1]
575
+
576
+ // Solo cambiar si el minuto actual no es válido para el primer tiempo
577
+ if (minEnd.value < firstMinute.minute || minEnd.value > lastMinute.minute) {
578
+ minEnd.value = lastMinute.minute
579
+ }
580
+
581
+ // Actualizar la posición del handler derecho
582
+ const endIndex = timelineMinutes.value.findIndex(
583
+ (m) => m.minute === minEnd.value && m.match_lapse === 1,
584
+ )
585
+ if (endIndex !== -1) {
586
+ rightHandlePosition.value = endIndex
587
+ }
588
+ }
589
+ } else if (endTime.value === '2') {
590
+ const secondHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 2)
591
+ if (secondHalfMinutes.length > 0) {
592
+ const firstMinute = secondHalfMinutes[0]
593
+ const lastMinute = secondHalfMinutes[secondHalfMinutes.length - 1]
594
+
595
+ // Solo cambiar si el minuto actual no es válido para el segundo tiempo
596
+ if (minEnd.value < firstMinute.minute || minEnd.value > lastMinute.minute) {
597
+ minEnd.value = lastMinute.minute
598
+ }
599
+
600
+ // Actualizar la posición del handler derecho
601
+ const endIndex = timelineMinutes.value.findIndex(
602
+ (m) => m.minute === minEnd.value && m.match_lapse === 2,
603
+ )
604
+ if (endIndex !== -1) {
605
+ rightHandlePosition.value = endIndex
606
+ }
607
+ }
608
+ }
609
+ }
610
+
611
+ // Resetear la bandera
612
+ isManualTimeChange.value = false
613
+
614
+ // Actualizar el ancho del rango
615
+ updateRangeWidth()
616
+ },
617
+ { immediate: true },
618
+ )
619
+
620
+ // Observar cambios en los inputs de minutos para validar y ajustar automáticamente
621
+ watch([minStart], () => {
622
+ // No ejecutar si estamos incrementando/decrementando o arrastrando
623
+ if (isIncrementing.value || isDragging.value) return
624
+
625
+ // Validar que el minuto esté dentro del rango del tiempo seleccionado
626
+ if (startTime.value === '1') {
627
+ const firstHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 1)
628
+ if (firstHalfMinutes.length > 0) {
629
+ const firstMinute = firstHalfMinutes[0]
630
+ const lastMinute = firstHalfMinutes[firstHalfMinutes.length - 1]
631
+
632
+ if (minStart.value < firstMinute.minute) {
633
+ minStart.value = firstMinute.minute
634
+ } else if (minStart.value > lastMinute.minute) {
635
+ minStart.value = lastMinute.minute
636
+ }
637
+
638
+ // Actualizar la posición del handler izquierdo
639
+ const startIndex = timelineMinutes.value.findIndex(
640
+ (m) => m.minute === minStart.value && m.match_lapse === 1,
641
+ )
642
+ if (startIndex !== -1) {
643
+ leftHandlePosition.value = startIndex
644
+ }
645
+ }
646
+ } else if (startTime.value === '2') {
647
+ const secondHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 2)
648
+ if (secondHalfMinutes.length > 0) {
649
+ const firstMinute = secondHalfMinutes[0]
650
+ const lastMinute = secondHalfMinutes[secondHalfMinutes.length - 1]
651
+
652
+ if (minStart.value < firstMinute.minute) {
653
+ minStart.value = firstMinute.minute
654
+ } else if (minStart.value > lastMinute.minute) {
655
+ minStart.value = lastMinute.minute
656
+ }
657
+
658
+ // Actualizar la posición del handler izquierdo
659
+ const startIndex = timelineMinutes.value.findIndex(
660
+ (m) => m.minute === minStart.value && m.match_lapse === 2,
661
+ )
662
+ if (startIndex !== -1) {
663
+ leftHandlePosition.value = startIndex
664
+ }
665
+ }
666
+ }
667
+
668
+ // Validar que el minuto inicial no sea mayor o igual que el minuto final
669
+ if (startTime.value === endTime.value && minStart.value >= minEnd.value) {
670
+ // Si están en el mismo tiempo y el minuto inicial es mayor o igual al final, ajustar el final
671
+ if (endTime.value === '1') {
672
+ const firstHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 1)
673
+ if (firstHalfMinutes.length > 0) {
674
+ const lastMinute = firstHalfMinutes[firstHalfMinutes.length - 1]
675
+ minEnd.value = Math.min(lastMinute.minute, minStart.value + 1)
676
+ }
677
+ } else if (endTime.value === '2') {
678
+ const secondHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 2)
679
+ if (secondHalfMinutes.length > 0) {
680
+ const lastMinute = secondHalfMinutes[secondHalfMinutes.length - 1]
681
+ minEnd.value = Math.min(lastMinute.minute, minStart.value + 1)
682
+ }
683
+ }
684
+ }
685
+
686
+ // Actualizar el ancho del rango
687
+ updateRangeWidth()
688
+ })
689
+
690
+ watch([minEnd], () => {
691
+ // No ejecutar si estamos incrementando/decrementando o arrastrando
692
+ if (isIncrementing.value || isDragging.value) return
693
+
694
+ // Validar que el minuto esté dentro del rango del tiempo seleccionado
695
+ if (endTime.value === '1') {
696
+ const firstHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 1)
697
+ if (firstHalfMinutes.length > 0) {
698
+ const firstMinute = firstHalfMinutes[0]
699
+ const lastMinute = firstHalfMinutes[firstHalfMinutes.length - 1]
700
+
701
+ if (minEnd.value < firstMinute.minute) {
702
+ minEnd.value = firstMinute.minute
703
+ } else if (minEnd.value > lastMinute.minute) {
704
+ minEnd.value = lastMinute.minute
705
+ }
706
+
707
+ // Actualizar la posición del handler derecho
708
+ const endIndex = timelineMinutes.value.findIndex(
709
+ (m) => m.minute === minEnd.value && m.match_lapse === 1,
710
+ )
711
+ if (endIndex !== -1) {
712
+ rightHandlePosition.value = endIndex
713
+ }
714
+ }
715
+ } else if (endTime.value === '2') {
716
+ const secondHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 2)
717
+
718
+ if (secondHalfMinutes.length > 0) {
719
+ const firstMinute = secondHalfMinutes[0]
720
+ const lastMinute = secondHalfMinutes[secondHalfMinutes.length - 1]
721
+
722
+ if (minEnd.value < firstMinute.minute) {
723
+ minEnd.value = firstMinute.minute
724
+ } else if (minEnd.value > lastMinute.minute) {
725
+ minEnd.value = lastMinute.minute
726
+ }
727
+
728
+ // Actualizar la posición del handler derecho
729
+ const endIndex = timelineMinutes.value.findIndex(
730
+ (m) => m.minute === minEnd.value && m.match_lapse === 2,
731
+ )
732
+ if (endIndex !== -1) {
733
+ rightHandlePosition.value = endIndex
734
+ }
735
+ }
736
+ }
737
+
738
+ // Validar que el minuto final no sea menor o igual que el minuto inicial
739
+ if (startTime.value === endTime.value && minEnd.value <= minStart.value) {
740
+ // Si están en el mismo tiempo y el minuto final es menor o igual al inicial, ajustar el inicial
741
+ if (startTime.value === '1') {
742
+ const firstHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 1)
743
+ if (firstHalfMinutes.length > 0) {
744
+ const firstMinute = firstHalfMinutes[0]
745
+ minStart.value = Math.max(firstMinute.minute, minEnd.value - 1)
746
+ }
747
+ } else if (startTime.value === '2') {
748
+ const secondHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 2)
749
+ if (secondHalfMinutes.length > 0) {
750
+ const firstMinute = secondHalfMinutes[0]
751
+ minStart.value = Math.max(firstMinute.minute, minEnd.value - 1)
752
+ }
753
+ }
754
+ }
755
+
756
+ // Actualizar el ancho del rango
757
+ updateRangeWidth()
758
+ })
759
+
760
+ // Función para calcular la posición en la línea de tiempo
761
+ function getPositionByIndex(index) {
762
+ const totalPositions = timelineMinutes.value.length
763
+ if (index < 0 || totalPositions === 0) return '0px'
764
+ if (totalPositions === 1) return '0px'
765
+ const position = (index / (totalPositions - 1)) * (props.timelineWidth - 40)
766
+ return `${position}px`
767
+ }
768
+
769
+ // Inicia el arrastre de los handles
770
+ function startDrag(handle, event) {
771
+ event.preventDefault() // Previene selección de texto
772
+ dragging = handle
773
+ dragStartX = event.type.includes('touch') ? event.touches[0].clientX : event.clientX
774
+ isActuallyDragging = false
775
+
776
+ // Guardar el índice inicial del handle que se está arrastrando
777
+ if (handle === 'left') {
778
+ initialHandleIndex.value = leftHandlePosition.value
779
+ } else if (handle === 'right') {
780
+ initialHandleIndex.value = rightHandlePosition.value
781
+ }
782
+
783
+ // Agrega listeners para mouse y touch
784
+ document.addEventListener('mousemove', onDrag)
785
+ document.addEventListener('touchmove', onDrag, { passive: false })
786
+ document.addEventListener('mouseup', stopDrag)
787
+ document.addEventListener('touchend', stopDrag)
788
+
789
+ // Actualiza el estado de arrastre
790
+ isDragging.value = true
791
+ }
792
+
793
+ // Función para manejar el arrastre
794
+ function onDrag(event) {
795
+ if (!dragging) return
796
+
797
+ event.preventDefault()
798
+
799
+ const currentX = event.type.includes('touch') ? event.touches[0].clientX : event.clientX
800
+
801
+ // Detectar si realmente se está arrastrando (movimiento mínimo de 5px)
802
+ if (!isActuallyDragging) {
803
+ const dragDistance = Math.abs(currentX - dragStartX)
804
+ if (dragDistance < 5) {
805
+ return // No hacer nada si no se ha movido lo suficiente
806
+ }
807
+ isActuallyDragging = true
808
+ }
809
+
810
+ const timelineWidth = getTimelineWidth()
811
+ const totalPositions = timelineMinutes.value.length
812
+
813
+ // Calcular el desplazamiento relativo desde la posición inicial
814
+ const dragOffset = currentX - dragStartX
815
+ const pixelsPerIndex = timelineWidth / (totalPositions - 1)
816
+ const indexOffset = Math.round(dragOffset / pixelsPerIndex)
817
+
818
+ // Calcular el nuevo índice basado en el índice inicial + el desplazamiento
819
+ let newIndex = initialHandleIndex.value + indexOffset
820
+ const clampedIndex = Math.max(0, Math.min(newIndex, totalPositions - 1))
821
+
822
+ if (dragging === 'left') {
823
+ // Para el handler izquierdo, solo verificar que no pase el handler derecho
824
+ const endIndex = timelineMinutes.value.findIndex(
825
+ (m) => m.minute === minEnd.value && m.match_lapse === parseInt(endTime.value),
826
+ )
827
+
828
+ // Permitir que el handler izquierdo se mueva libremente, solo bloquear si está muy cerca del derecho
829
+ if (clampedIndex >= endIndex - 1) {
830
+ return
831
+ }
832
+
833
+ const selectedMinute = timelineMinutes.value[clampedIndex]
834
+
835
+ // Marcar que estamos arrastrando para evitar interferencia de watchers
836
+ isDragging.value = true
837
+
838
+ // Actualizar posición y valores de manera síncrona
839
+ leftHandlePosition.value = clampedIndex
840
+ minStart.value = selectedMinute.minute
841
+ startTime.value = selectedMinute.match_lapse.toString()
842
+
843
+ // Marcar como cambio manual para evitar que los watchers interfieran
844
+ isManualTimeChange.value = true
845
+ } else if (dragging === 'right') {
846
+ // Para el handler derecho, solo verificar que no pase el handler izquierdo
847
+ const startIndex = timelineMinutes.value.findIndex(
848
+ (m) => m.minute === minStart.value && m.match_lapse === parseInt(startTime.value),
849
+ )
850
+
851
+ // Permitir que el handler derecho se mueva libremente, solo bloquear si está muy cerca del izquierdo
852
+ if (clampedIndex <= startIndex + 1) {
853
+ return
854
+ }
855
+
856
+ const selectedMinute = timelineMinutes.value[clampedIndex]
857
+
858
+ // Marcar que estamos arrastrando para evitar interferencia de watchers
859
+ isDragging.value = true
860
+
861
+ // Actualizar posición y valores de manera síncrona
862
+ rightHandlePosition.value = clampedIndex
863
+ minEnd.value = selectedMinute.minute
864
+ endTime.value = selectedMinute.match_lapse.toString()
865
+
866
+ // Marcar como cambio manual para evitar que los watchers interfieran
867
+ isManualTimeChange.value = true
868
+ }
869
+
870
+ // Calcular y actualizar el ancho del rango inmediatamente
871
+ const startIndex = timelineMinutes.value.findIndex(
872
+ (m) => m.minute === minStart.value && m.match_lapse === parseInt(startTime.value),
873
+ )
874
+ const endIndex = timelineMinutes.value.findIndex(
875
+ (m) => m.minute === minEnd.value && m.match_lapse === parseInt(endTime.value),
876
+ )
877
+
878
+ if (startIndex !== -1 && endIndex !== -1 && startIndex < endIndex) {
879
+ const totalPositions = timelineMinutes.value.length
880
+ const startPos = (startIndex / (totalPositions - 1)) * (props.timelineWidth - 40)
881
+ const endPos = (endIndex / (totalPositions - 1)) * (props.timelineWidth - 40)
882
+ rangeWidth.value = `${endPos - startPos}px`
883
+ }
884
+
885
+ // Forzar la actualización de la vista
886
+ nextTick(() => {
887
+ handleRangeChange()
888
+ })
889
+ }
890
+
891
+ // Finaliza el arrastre
892
+ function stopDrag() {
893
+ if (dragging) {
894
+ // Solo validar que los valores estén en rangos válidos, sin forzar ajustes
895
+ if (minStart.value < 0) minStart.value = 0
896
+ if (minEnd.value > minTotal.value) minEnd.value = minTotal.value
897
+
898
+ // Resetear las banderas después de un pequeño delay para permitir que los watchers funcionen
899
+ nextTick(() => {
900
+ isDragging.value = false
901
+ isManualTimeChange.value = false
902
+ })
903
+
904
+ // Emitir los valores finales
905
+ handleRangeChange()
906
+ }
907
+
908
+ dragging = null
909
+ document.removeEventListener('mousemove', onDrag)
910
+ document.removeEventListener('touchmove', onDrag)
911
+ document.removeEventListener('mouseup', stopDrag)
912
+ document.removeEventListener('touchend', stopDrag)
913
+ }
914
+
915
+ function decrementMinStart() {
916
+ if (minStart.value > 0) {
917
+ isIncrementing.value = true // Marcar que estamos decrementando
918
+
919
+ let newValue = minStart.value - 1
920
+ let timeChanged = false
921
+ let newTime = startTime.value
922
+
923
+ // Obtener el primer minuto del tiempo actual desde el array
924
+ if (startTime.value === '1') {
925
+ const firstHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 1)
926
+ if (firstHalfMinutes.length > 0) {
927
+ const firstMinute = firstHalfMinutes[0]
928
+ if (newValue < firstMinute.minute) {
929
+ // Si se pasa del primer minuto del primer tiempo, no hacer nada
930
+ // (no cambiar al segundo tiempo al decrementar)
931
+ newValue = firstMinute.minute
932
+ }
933
+ }
934
+ } else if (startTime.value === '2') {
935
+ const secondHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 2)
936
+ if (secondHalfMinutes.length > 0) {
937
+ const firstMinute = secondHalfMinutes[0]
938
+ if (newValue < firstMinute.minute) {
939
+ // Si se pasa del primer minuto del segundo tiempo, cambiar al primer tiempo
940
+ newTime = '1'
941
+ timeChanged = true
942
+ const firstHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 1)
943
+ if (firstHalfMinutes.length > 0) {
944
+ const lastMinute = firstHalfMinutes[firstHalfMinutes.length - 1]
945
+ newValue = lastMinute.minute
946
+ }
947
+ }
948
+ }
949
+ }
950
+
951
+ // Actualizar posición y valores de manera síncrona
952
+ const startIndex = timelineMinutes.value.findIndex(
953
+ (m) => m.minute === newValue && m.match_lapse === parseInt(newTime),
954
+ )
955
+
956
+ if (startIndex !== -1) {
957
+ // Actualizar todo de manera síncrona
958
+ leftHandlePosition.value = startIndex
959
+ minStart.value = newValue
960
+
961
+ if (timeChanged) {
962
+ startTime.value = newTime
963
+ isManualTimeChange.value = true
964
+ }
965
+
966
+ // Actualizar el ancho del rango inmediatamente
967
+ updateRangeWidth()
968
+ }
969
+
970
+ // Resetear la bandera después de un pequeño delay
971
+ nextTick(() => {
972
+ isIncrementing.value = false
973
+ })
974
+ }
975
+ }
976
+
977
+ function incrementMinEnd() {
978
+ if (minEnd.value < minTotal.value) {
979
+ isIncrementing.value = true // Marcar que estamos incrementando
980
+
981
+ let newValue = minEnd.value + 1
982
+ let timeChanged = false
983
+ let newTime = endTime.value
984
+
985
+ // No permitir que minEnd sea menor o igual a minStart en el mismo tiempo
986
+ if (newTime === startTime.value && newValue <= minStart.value) {
987
+ nextTick(() => {
988
+ isIncrementing.value = false
989
+ })
990
+ return
991
+ }
992
+
993
+ // Obtener el último minuto del tiempo actual desde el array
994
+ if (endTime.value === '1') {
995
+ const firstHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 1)
996
+ if (firstHalfMinutes.length > 0) {
997
+ const lastMinute = firstHalfMinutes[firstHalfMinutes.length - 1]
998
+ if (newValue > lastMinute.minute) {
999
+ // Si se pasa del último minuto del primer tiempo, cambiar al segundo tiempo
1000
+ newTime = '2'
1001
+ timeChanged = true
1002
+ const secondHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 2)
1003
+ if (secondHalfMinutes.length > 0) {
1004
+ const firstMinute = secondHalfMinutes[0]
1005
+ newValue = firstMinute.minute
1006
+ }
1007
+ }
1008
+ }
1009
+ } else if (endTime.value === '2') {
1010
+ const secondHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 2)
1011
+ if (secondHalfMinutes.length > 0) {
1012
+ const lastMinute = secondHalfMinutes[secondHalfMinutes.length - 1]
1013
+ if (newValue > lastMinute.minute) {
1014
+ newValue = lastMinute.minute
1015
+ }
1016
+ }
1017
+ }
1018
+
1019
+ // Validar que el nuevo tiempo no sea menor que el tiempo inicial
1020
+ if (parseInt(newTime) < parseInt(startTime.value)) {
1021
+ // Si el nuevo tiempo es menor, ajustar el tiempo inicial
1022
+ startTime.value = newTime
1023
+ isManualTimeChange.value = true
1024
+
1025
+ // Ajustar también el minuto inicial si es necesario
1026
+ if (newTime === '1') {
1027
+ const firstHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 1)
1028
+ if (firstHalfMinutes.length > 0) {
1029
+ const firstMinute = firstHalfMinutes[0]
1030
+ if (minStart.value > newValue) {
1031
+ minStart.value = firstMinute.minute
1032
+ }
1033
+ }
1034
+ } else if (newTime === '2') {
1035
+ const secondHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 2)
1036
+ if (secondHalfMinutes.length > 0) {
1037
+ const firstMinute = secondHalfMinutes[0]
1038
+ if (minStart.value > newValue) {
1039
+ minStart.value = firstMinute.minute
1040
+ }
1041
+ }
1042
+ }
1043
+ }
1044
+
1045
+ // Actualizar posición y valores de manera síncrona
1046
+ const endIndex = timelineMinutes.value.findIndex(
1047
+ (m) => m.minute === newValue && m.match_lapse === parseInt(newTime),
1048
+ )
1049
+
1050
+ if (endIndex !== -1) {
1051
+ // Actualizar todo de manera síncrona
1052
+ rightHandlePosition.value = endIndex
1053
+ minEnd.value = newValue
1054
+
1055
+ if (timeChanged) {
1056
+ endTime.value = newTime
1057
+ isManualTimeChange.value = true
1058
+ }
1059
+
1060
+ // Actualizar el ancho del rango inmediatamente
1061
+ updateRangeWidth()
1062
+ }
1063
+
1064
+ // Resetear la bandera después de un pequeño delay
1065
+ nextTick(() => {
1066
+ isIncrementing.value = false
1067
+ })
1068
+ }
1069
+ }
1070
+
1071
+ function decrementMinEnd() {
1072
+ // Verificar si podemos decrementar o cambiar de tiempo
1073
+ let canDecrement = false
1074
+ let newValue = minEnd.value - 1
1075
+ let newTime = endTime.value
1076
+
1077
+ // No permitir que minEnd sea menor o igual a minStart en el mismo tiempo
1078
+ if (newTime === startTime.value && newValue <= minStart.value) {
1079
+ return
1080
+ }
1081
+
1082
+ // Verificar si podemos decrementar en el tiempo actual
1083
+ if (endTime.value === '1') {
1084
+ const firstHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 1)
1085
+ if (firstHalfMinutes.length > 0) {
1086
+ const firstMinute = firstHalfMinutes[0]
1087
+ if (newValue >= firstMinute.minute) {
1088
+ canDecrement = true
1089
+ }
1090
+ }
1091
+ } else if (endTime.value === '2') {
1092
+ const secondHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 2)
1093
+ if (secondHalfMinutes.length > 0) {
1094
+ const firstMinute = secondHalfMinutes[0]
1095
+ if (newValue >= firstMinute.minute) {
1096
+ canDecrement = true
1097
+ } else {
1098
+ // Si no podemos decrementar en el segundo tiempo, intentar cambiar al primer tiempo
1099
+ const firstHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 1)
1100
+ if (firstHalfMinutes.length > 0) {
1101
+ const lastMinute = firstHalfMinutes[firstHalfMinutes.length - 1]
1102
+ newTime = '1'
1103
+ newValue = lastMinute.minute
1104
+ canDecrement = true
1105
+ }
1106
+ }
1107
+ }
1108
+ }
1109
+
1110
+ if (canDecrement) {
1111
+ isIncrementing.value = true // Marcar que estamos decrementando
1112
+
1113
+ let timeChanged = false
1114
+
1115
+ // Si cambiamos de tiempo, marcar como cambio
1116
+ if (newTime !== endTime.value) {
1117
+ timeChanged = true
1118
+ }
1119
+
1120
+ // Actualizar posición y valores de manera síncrona
1121
+ const endIndex = timelineMinutes.value.findIndex(
1122
+ (m) => m.minute === newValue && m.match_lapse === parseInt(newTime),
1123
+ )
1124
+ if (endIndex !== -1) {
1125
+ // Actualizar todo de manera síncrona
1126
+ rightHandlePosition.value = endIndex
1127
+ minEnd.value = newValue
1128
+
1129
+ if (timeChanged) {
1130
+ endTime.value = newTime
1131
+ isManualTimeChange.value = true
1132
+ }
1133
+
1134
+ // Actualizar el ancho del rango inmediatamente
1135
+ updateRangeWidth()
1136
+ }
1137
+
1138
+ // Resetear la bandera después de un pequeño delay
1139
+ nextTick(() => {
1140
+ isIncrementing.value = false
1141
+ })
1142
+ }
1143
+ }
1144
+
1145
+ // Función para el scroll horizontal
1146
+ function scrollLeft() {
1147
+ const scrollContainer = document.querySelector('.timeline-scroll')
1148
+ if (scrollContainer) {
1149
+ const currentScroll = scrollContainer.scrollLeft
1150
+ const newScroll = Math.max(0, currentScroll - 150)
1151
+ scrollContainer.scrollTo({ left: newScroll, behavior: 'smooth' })
1152
+ setTimeout(checkScroll, 300)
1153
+ }
1154
+ }
1155
+
1156
+ function scrollRight() {
1157
+ const scrollContainer = document.querySelector('.timeline-scroll')
1158
+ if (scrollContainer) {
1159
+ const currentScroll = scrollContainer.scrollLeft
1160
+ const maxScroll = scrollContainer.scrollWidth - scrollContainer.clientWidth
1161
+ const newScroll = Math.min(maxScroll, currentScroll + 150)
1162
+ scrollContainer.scrollTo({ left: newScroll, behavior: 'smooth' })
1163
+ setTimeout(checkScroll, 300)
1164
+ }
1165
+ }
1166
+
1167
+ // Obtiene el ancho real del timeline
1168
+ function getTimelineWidth() {
1169
+ if (!timelineRef.value) return 600 // Valor por defecto
1170
+ return timelineRef.value.getBoundingClientRect().width
1171
+ }
1172
+
1173
+ // Función para emitir los valores en segundos y minutos
1174
+ function handleRangeChange() {
1175
+ const startSeconds = minStart.value * 60
1176
+ const endSeconds = minEnd.value * 60
1177
+ emit('range-change', {
1178
+ start: {
1179
+ minutes: minStart.value,
1180
+ seconds: startSeconds,
1181
+ time: startTime.value,
1182
+ match_lapse: parseInt(startTime.value),
1183
+ },
1184
+ end: {
1185
+ minutes: minEnd.value,
1186
+ seconds: endSeconds,
1187
+ time: endTime.value,
1188
+ match_lapse: parseInt(endTime.value),
1189
+ },
1190
+ })
1191
+ }
1192
+
1193
+ // Función para actualizar el ancho del rango
1194
+ function updateRangeWidth() {
1195
+ const startIndex = timelineMinutes.value.findIndex(
1196
+ (m) => m.minute === minStart.value && m.match_lapse === parseInt(startTime.value),
1197
+ )
1198
+ const endIndex = timelineMinutes.value.findIndex(
1199
+ (m) => m.minute === minEnd.value && m.match_lapse === parseInt(endTime.value),
1200
+ )
1201
+
1202
+ if (startIndex !== -1 && endIndex !== -1 && startIndex < endIndex) {
1203
+ const totalPositions = timelineMinutes.value.length
1204
+ const startPos = (startIndex / (totalPositions - 1)) * (props.timelineWidth - 40)
1205
+ const endPos = (endIndex / (totalPositions - 1)) * (props.timelineWidth - 40)
1206
+ rangeWidth.value = `${endPos - startPos}px`
1207
+ }
1208
+ }
1209
+
1210
+ function incrementMinStart() {
1211
+ isIncrementing.value = true // Marcar que estamos incrementando
1212
+
1213
+ let newValue = minStart.value + 1
1214
+ let timeChanged = false
1215
+ let newTime = startTime.value
1216
+
1217
+ // No permitir que minStart sea mayor o igual a minEnd en el mismo tiempo
1218
+ if (newTime === endTime.value && newValue >= minEnd.value) {
1219
+ nextTick(() => {
1220
+ isIncrementing.value = false
1221
+ })
1222
+ return
1223
+ }
1224
+
1225
+ // Obtener el último minuto del tiempo actual desde el array
1226
+ if (startTime.value === '1') {
1227
+ const firstHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 1)
1228
+ if (firstHalfMinutes.length > 0) {
1229
+ const lastMinute = firstHalfMinutes[firstHalfMinutes.length - 1]
1230
+ if (newValue > lastMinute.minute) {
1231
+ // Si se pasa del último minuto del primer tiempo, cambiar al segundo tiempo
1232
+ newTime = '2'
1233
+ timeChanged = true
1234
+ const secondHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 2)
1235
+ if (secondHalfMinutes.length > 0) {
1236
+ const firstMinute = secondHalfMinutes[0]
1237
+ newValue = firstMinute.minute
1238
+ }
1239
+ }
1240
+ }
1241
+ } else if (startTime.value === '2') {
1242
+ const secondHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 2)
1243
+ if (secondHalfMinutes.length > 0) {
1244
+ const lastMinute = secondHalfMinutes[secondHalfMinutes.length - 1]
1245
+ if (newValue > lastMinute.minute) {
1246
+ newValue = lastMinute.minute
1247
+ }
1248
+ }
1249
+ }
1250
+
1251
+ // Validar que el nuevo tiempo no sea mayor que el tiempo final
1252
+ if (parseInt(newTime) > parseInt(endTime.value)) {
1253
+ // Si el nuevo tiempo es mayor, ajustar el tiempo final
1254
+ endTime.value = newTime
1255
+ isManualTimeChange.value = true
1256
+
1257
+ // Ajustar también el minuto final si es necesario
1258
+ if (newTime === '1') {
1259
+ const firstHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 1)
1260
+ if (firstHalfMinutes.length > 0) {
1261
+ const lastMinute = firstHalfMinutes[firstHalfMinutes.length - 1]
1262
+ if (minEnd.value < newValue) {
1263
+ minEnd.value = lastMinute.minute
1264
+ }
1265
+ }
1266
+ } else if (newTime === '2') {
1267
+ const secondHalfMinutes = timelineMinutes.value.filter((m) => m.match_lapse === 2)
1268
+ if (secondHalfMinutes.length > 0) {
1269
+ const lastMinute = secondHalfMinutes[secondHalfMinutes.length - 1]
1270
+ if (minEnd.value < newValue) {
1271
+ minEnd.value = lastMinute.minute
1272
+ }
1273
+ }
1274
+ }
1275
+ }
1276
+
1277
+ // Actualizar posición y valores de manera síncrona
1278
+ const startIndex = timelineMinutes.value.findIndex(
1279
+ (m) => m.minute === newValue && m.match_lapse === parseInt(newTime),
1280
+ )
1281
+
1282
+ if (startIndex !== -1) {
1283
+ // Actualizar todo de manera síncrona
1284
+ leftHandlePosition.value = startIndex
1285
+ minStart.value = newValue
1286
+
1287
+ if (timeChanged) {
1288
+ startTime.value = newTime
1289
+ isManualTimeChange.value = true
1290
+ }
1291
+
1292
+ // Actualizar el ancho del rango inmediatamente
1293
+ updateRangeWidth()
1294
+ }
1295
+
1296
+ // Resetear la bandera después de un pequeño delay
1297
+ nextTick(() => {
1298
+ isIncrementing.value = false
1299
+ })
1300
+ }
1301
+ </script>
1302
+
1303
+ <template>
1304
+ <div
1305
+ class="timeline"
1306
+ ref="timelineRef"
1307
+ :class="{ 'is-dragging': isDragging }"
1308
+ :style="{ width: `${containerWidth}px` }"
1309
+ >
1310
+ <!-- Encabezado con inputs para el rango manual -->
1311
+ <div
1312
+ class="timeline-header responsive-header"
1313
+ v-if="false"
1314
+ :class="{
1315
+ 'small-screen': containerWidth < 470,
1316
+ 'very-small-screen': containerWidth < 420,
1317
+ 'extra-small-screen': containerWidth < 370,
1318
+ 'mobile-column': containerWidth < 500,
1319
+ 'tablet-layout': containerWidth < 800,
1320
+ 'mobile-layout': containerWidth < 580,
1321
+ }"
1322
+ >
1323
+ <div class="header-row">
1324
+ <span class="header-title">Considerar eventos del </span>
1325
+ </div>
1326
+ <div class="header-row controls-row">
1327
+ <select v-model="startTime" class="time-select">
1328
+ <option value="1">Primer tiempo</option>
1329
+ <option value="2">Segundo tiempo</option>
1330
+ </select>
1331
+ <div class="input-wrapper">
1332
+ <div class="input-container">
1333
+ <span class="input-label">min</span>
1334
+ <input
1335
+ type="number"
1336
+ v-model="minStart"
1337
+ readonly
1338
+ :min="
1339
+ startTime === '1'
1340
+ ? timelineMinutes.filter((m) => m.match_lapse === 1)[0]?.minute || 0
1341
+ : timelineMinutes.filter((m) => m.match_lapse === 2)[0]?.minute || 45
1342
+ "
1343
+ :max="
1344
+ startTime === '1'
1345
+ ? timelineMinutes.filter((m) => m.match_lapse === 1).slice(-1)[0]?.minute || 45
1346
+ : timelineMinutes.filter((m) => m.match_lapse === 2).slice(-1)[0]?.minute || 96
1347
+ "
1348
+ />
1349
+ <div class="input-arrows">
1350
+ <button class="arrow-up" @click="incrementMinStart">
1351
+ <svg
1352
+ width="10"
1353
+ height="6"
1354
+ viewBox="0 0 10 6"
1355
+ fill="none"
1356
+ xmlns="http://www.w3.org/2000/svg"
1357
+ >
1358
+ <path
1359
+ d="M1 5L5 1L9 5"
1360
+ stroke="currentColor"
1361
+ stroke-width="1.5"
1362
+ stroke-linecap="round"
1363
+ stroke-linejoin="round"
1364
+ />
1365
+ </svg>
1366
+ </button>
1367
+ <button class="arrow-down" @click="decrementMinStart">
1368
+ <svg
1369
+ width="10"
1370
+ height="6"
1371
+ viewBox="0 0 10 6"
1372
+ fill="none"
1373
+ xmlns="http://www.w3.org/2000/svg"
1374
+ >
1375
+ <path
1376
+ d="M1 1L5 5L9 1"
1377
+ stroke="currentColor"
1378
+ stroke-width="1.5"
1379
+ stroke-linecap="round"
1380
+ stroke-linejoin="round"
1381
+ />
1382
+ </svg>
1383
+ </button>
1384
+ </div>
1385
+ </div>
1386
+ </div>
1387
+ <span class="to-text">al</span>
1388
+ <select v-model="endTime" class="time-select">
1389
+ <option value="1">Primer tiempo</option>
1390
+ <option value="2">Segundo tiempo</option>
1391
+ </select>
1392
+ <div class="input-wrapper">
1393
+ <div class="input-container">
1394
+ <span class="input-label">min</span>
1395
+ <input
1396
+ type="number"
1397
+ v-model="minEnd"
1398
+ readonly
1399
+ :min="
1400
+ endTime === '1'
1401
+ ? timelineMinutes.filter((m) => m.match_lapse === 1)[0]?.minute || 0
1402
+ : timelineMinutes.filter((m) => m.match_lapse === 2)[0]?.minute || 45
1403
+ "
1404
+ :max="
1405
+ endTime === '1'
1406
+ ? timelineMinutes.filter((m) => m.match_lapse === 1).slice(-1)[0]?.minute || 45
1407
+ : timelineMinutes.filter((m) => m.match_lapse === 2).slice(-1)[0]?.minute || 96
1408
+ "
1409
+ />
1410
+ <div class="input-arrows">
1411
+ <button class="arrow-up" @click="incrementMinEnd">
1412
+ <svg
1413
+ width="10"
1414
+ height="6"
1415
+ viewBox="0 0 10 6"
1416
+ fill="none"
1417
+ xmlns="http://www.w3.org/2000/svg"
1418
+ >
1419
+ <path
1420
+ d="M1 5L5 1L9 5"
1421
+ stroke="currentColor"
1422
+ stroke-width="1.5"
1423
+ stroke-linecap="round"
1424
+ stroke-linejoin="round"
1425
+ />
1426
+ </svg>
1427
+ </button>
1428
+ <button class="arrow-down" @click="decrementMinEnd">
1429
+ <svg
1430
+ width="10"
1431
+ height="6"
1432
+ viewBox="0 0 10 6"
1433
+ fill="none"
1434
+ xmlns="http://www.w3.org/2000/svg"
1435
+ >
1436
+ <path
1437
+ d="M1 1L5 5L9 1"
1438
+ stroke="currentColor"
1439
+ stroke-width="1.5"
1440
+ stroke-linecap="round"
1441
+ stroke-linejoin="round"
1442
+ />
1443
+ </svg>
1444
+ </button>
1445
+ </div>
1446
+ </div>
1447
+ </div>
1448
+ </div>
1449
+ </div>
1450
+ <!-- Contenedor con scroll para móvil -->
1451
+ <div class="timeline-container">
1452
+ <!-- Scroll y flechas ocultos -->
1453
+ <div class="timeline-scroll no-scrollbar" ref="scrollContainer" @scroll="checkScroll">
1454
+ <div class="timeline-bar" :style="{ width: `${timelineWidth}px` }">
1455
+ <!-- Círculos con logos de equipo -->
1456
+ <div class="team-circle team-circle-top">
1457
+ <img
1458
+ :src="
1459
+ props.isDefault
1460
+ ? 'https://golstatsimages.blob.core.windows.net/todoelfut/lineups/escudo1.png'
1461
+ : `https://golstatsimages.blob.core.windows.net/teams-80/${props.homeTeam}.png`
1462
+ "
1463
+ alt="Equipo local"
1464
+ />
1465
+ </div>
1466
+ <div class="team-circle team-circle-bottom">
1467
+ <img
1468
+ :src="
1469
+ props.isDefault
1470
+ ? 'https://golstatsimages.blob.core.windows.net/todoelfut/lineups/escudo2.png'
1471
+ : `https://golstatsimages.blob.core.windows.net/teams-80/${props.awayTeam}.png`
1472
+ "
1473
+ alt="Equipo visitante"
1474
+ />
1475
+ </div>
1476
+
1477
+ <!-- Línea de tiempo única -->
1478
+ <div class="timeline-line">
1479
+ <div class="line"></div>
1480
+
1481
+ <!-- Marcador inicial fijo (minuto 0) -->
1482
+ <span
1483
+ class="minute-ball minute-ball-initial minute-ball-center"
1484
+ :style="{ left: getPositionByIndex(0) }"
1485
+ >0'</span
1486
+ >
1487
+
1488
+ <!-- Eventos -->
1489
+ <template v-for="(minute, idx) in timelineMinutes">
1490
+ <div
1491
+ v-for="(event, idxEvent) in minute.event"
1492
+ :key="'event-' + idx + '-' + idxEvent"
1493
+ class="event"
1494
+ :style="{
1495
+ left:
1496
+ idxEvent === 0
1497
+ ? getPositionByIndex(idx - 1.5)
1498
+ : getPositionByIndex(idx - 1.5 + idxEvent * 0.3),
1499
+ }"
1500
+ >
1501
+ <span v-if="event?.team === 'local'" class="event-icon event-icon-top">
1502
+ <template v-if="event?.icon === 'icon-yellow-card'">
1503
+ <svg
1504
+ width="24"
1505
+ height="24"
1506
+ viewBox="0 0 24 24"
1507
+ fill="none"
1508
+ xmlns="http://www.w3.org/2000/svg"
1509
+ >
1510
+ <rect
1511
+ x="0.507812"
1512
+ y="0.375488"
1513
+ width="22.7873"
1514
+ height="22.8364"
1515
+ rx="11.3937"
1516
+ fill="none"
1517
+ />
1518
+ <rect
1519
+ x="8"
1520
+ y="7"
1521
+ width="6.8362"
1522
+ height="9.13458"
1523
+ rx="2.28119"
1524
+ fill="#F7C330"
1525
+ />
1526
+ </svg>
1527
+ </template>
1528
+ <template v-else-if="event?.icon === 'icon-red-card'">
1529
+ <svg
1530
+ width="23"
1531
+ height="23"
1532
+ viewBox="0 0 23 23"
1533
+ fill="none"
1534
+ xmlns="http://www.w3.org/2000/svg"
1535
+ >
1536
+ <rect width="22.7873" height="22.8364" rx="11.3937" fill="none" />
1537
+ <rect
1538
+ x="8"
1539
+ y="7"
1540
+ width="6.8362"
1541
+ height="9.13458"
1542
+ rx="2.28119"
1543
+ fill="#E5152D"
1544
+ />
1545
+ </svg>
1546
+ </template>
1547
+ <template v-else-if="event?.icon === 'icon-goal'">
1548
+ <svg
1549
+ width="24"
1550
+ height="24"
1551
+ viewBox="0 0 48 48"
1552
+ fill="none"
1553
+ xmlns="http://www.w3.org/2000/svg"
1554
+ >
1555
+ <circle fill="none" cx="24" cy="24" r="24" />
1556
+ <ellipse fill="none" cx="24" cy="24" rx="14.82" ry="14.85" />
1557
+ <path
1558
+ fill="#fff"
1559
+ d="M24.03,36.05c-6.65,0-12.05-5.41-12.05-12.05s5.41-12.05,12.05-12.05,12.05,5.41,12.05,12.05-5.41,12.05-12.05,12.05Zm0-23.1c-6.1,0-11.05,4.96-11.05,11.05s4.96,11.05,11.05,11.05,11.05-4.96,11.05-11.05-4.96-11.05-11.05-11.05Z"
1560
+ />
1561
+ <path
1562
+ fill="#fff"
1563
+ d="M27.22,29.38h-6.35c-.22,0-.41-.14-.48-.35l-1.96-6.06c-.07-.21,0-.43,.18-.56l5.14-3.74c.18-.13,.41-.13,.59,0l5.14,3.74c.17,.13,.25,.35,.18,.56l-1.96,6.06c-.07,.21-.26,.35-.48,.35Zm-5.99-1h5.62l1.74-5.37-4.55-3.32-4.55,3.32,1.74,5.37Z"
1564
+ />
1565
+ <path
1566
+ fill="#fff"
1567
+ d="M24.06,15.71c-.07,0-.13-.01-.2-.04l-4.38-1.87c-.25-.11-.37-.4-.26-.66,.11-.25,.4-.37,.66-.26l4.18,1.78,4.18-1.78c.25-.11,.55,0,.66,.26,.11,.25,0,.55-.26,.66l-4.38,1.87c-.06,.03-.13,.04-.2,.04Z"
1568
+ />
1569
+ <path
1570
+ fill="#fff"
1571
+ d="M12.62,25.37c-.12,0-.23-.04-.33-.12-.21-.18-.23-.5-.05-.71l2.99-3.44-.4-4.54c-.02-.27,.18-.52,.45-.54,.27-.03,.52,.18,.54,.45l.42,4.75c.01,.14-.03,.27-.12,.37l-3.12,3.6c-.1,.11-.24,.17-.38,.17Z"
1572
+ />
1573
+ <path
1574
+ fill="#fff"
1575
+ d="M21.37,35.66c-.17,0-.34-.09-.43-.24l-2.34-3.91-4.43-1.02c-.27-.06-.44-.33-.38-.6s.33-.44,.6-.38l4.64,1.07c.13,.03,.25,.11,.32,.23l2.45,4.09c.14,.24,.06,.54-.17,.69-.08,.05-.17,.07-.26,.07Z"
1576
+ />
1577
+ <path
1578
+ fill="#fff"
1579
+ d="M26.75,35.66c-.09,0-.18-.02-.26-.07-.24-.14-.31-.45-.17-.69l2.44-4.09c.07-.12,.18-.2,.32-.23l4.63-1.07c.27-.06,.54,.11,.6,.38s-.11,.54-.38,.6l-4.43,1.02-2.33,3.91c-.09,.16-.26,.24-.43,.24Z"
1580
+ />
1581
+ <path
1582
+ fill="#fff"
1583
+ d="M35.5,25.37c-.14,0-.28-.06-.38-.17l-3.13-3.6c-.09-.1-.13-.24-.12-.37l.42-4.75c.02-.27,.27-.48,.54-.45,.28,.02,.48,.27,.45,.54l-.4,4.54,2.99,3.44c.18,.21,.16,.52-.05,.71-.09,.08-.21,.12-.33,.12Z"
1584
+ />
1585
+ <path
1586
+ fill="#fff"
1587
+ d="M24.05,19.58c-.28,0-.5-.22-.5-.5v-3.87c0-.28,.22-.5,.5-.5s.5,.22,.5,.5v3.87c0,.28-.22,.5-.5,.5Z"
1588
+ />
1589
+ <path
1590
+ fill="#fff"
1591
+ d="M29.21,23.47c-.18,0-.35-.1-.44-.26-.13-.24-.04-.55,.2-.68l3.17-1.7c.25-.13,.55-.04,.68,.2,.13,.24,.04,.55-.2,.68l-3.17,1.7c-.08,.04-.16,.06-.24,.06Z"
1592
+ />
1593
+ <path
1594
+ fill="#fff"
1595
+ d="M29.2,31.57c-.14,0-.27-.06-.37-.17l-1.96-2.19c-.18-.21-.17-.52,.04-.71,.21-.18,.52-.17,.71,.04l1.96,2.19c.18,.21,.17,.52-.04,.71-.1,.09-.21,.13-.33,.13Z"
1596
+ />
1597
+ <path
1598
+ fill="#fff"
1599
+ d="M18.91,31.57c-.12,0-.24-.04-.33-.13-.21-.18-.22-.5-.04-.71l1.96-2.19c.19-.21,.5-.22,.71-.04,.21,.18,.22,.5,.04,.71l-1.96,2.19c-.1,.11-.24,.17-.37,.17Z"
1600
+ />
1601
+ <path
1602
+ fill="#fff"
1603
+ d="M18.93,23.32c-.07,0-.15-.02-.22-.05l-3.17-1.55c-.25-.12-.35-.42-.23-.67,.12-.25,.42-.35,.67-.23l3.17,1.55c.25,.12,.35,.42,.23,.67-.09,.18-.26,.28-.45,.28Z"
1604
+ />
1605
+ </svg>
1606
+ </template>
1607
+ <template v-else-if="event?.icon === 'icon-change'">
1608
+ <svg
1609
+ width="24"
1610
+ height="24"
1611
+ viewBox="0 0 48 48"
1612
+ fill="none"
1613
+ xmlns="http://www.w3.org/2000/svg"
1614
+ >
1615
+ <circle fill="none" cx="24" cy="24" r="24" />
1616
+ <path
1617
+ fill="#fff"
1618
+ d="M31.62,23.86c-.19,0-.37-.07-.52-.21-.3-.29-.31-.76-.03-1.06l2.89-3.04-2.89-3.04c-.29-.3-.27-.77,.03-1.06,.3-.29,.77-.27,1.06,.03l3.39,3.56c.28,.29,.28,.74,0,1.03l-3.39,3.56c-.15,.15-.34,.23-.54,.23Z"
1619
+ />
1620
+ <path
1621
+ fill="#fff"
1622
+ d="M34.99,20.31H16.37c-.41,0-.75-.34-.75-.75s.34-.75,.75-.75h18.62c.41,0,.75,.34,.75,.75s-.34,.75-.75,.75Z"
1623
+ />
1624
+ <path
1625
+ fill="#fff"
1626
+ d="M16.38,32.75c-.2,0-.4-.08-.54-.23l-3.38-3.56c-.28-.29-.28-.74,0-1.03l3.38-3.56c.28-.3,.76-.31,1.06-.03,.3,.29,.31,.76,.03,1.06l-2.89,3.04,2.89,3.04c.29,.3,.27,.78-.03,1.06-.15,.14-.33,.21-.52,.21Z"
1627
+ />
1628
+ <path
1629
+ fill="#fff"
1630
+ d="M31.62,29.19H13c-.41,0-.75-.34-.75-.75s.34-.75,.75-.75H31.62c.41,0,.75,.34,.75,.75s-.34,.75-.75,.75Z"
1631
+ />
1632
+ </svg>
1633
+ </template>
1634
+ <span v-else :class="event?.icon"></span>
1635
+ </span>
1636
+ <span class="minute-ball minute-ball-center"
1637
+ >{{ event?.minuteLabel || minute.minute }}'</span
1638
+ >
1639
+ <span v-if="event?.team === 'visitante'" class="event-icon event-icon-bottom">
1640
+ <template v-if="event?.icon === 'icon-yellow-card'">
1641
+ <svg
1642
+ width="24"
1643
+ height="24"
1644
+ viewBox="0 0 24 24"
1645
+ fill="none"
1646
+ xmlns="http://www.w3.org/2000/svg"
1647
+ >
1648
+ <rect
1649
+ x="0.507812"
1650
+ y="0.375488"
1651
+ width="22.7873"
1652
+ height="22.8364"
1653
+ rx="11.3937"
1654
+ fill="none"
1655
+ />
1656
+ <rect
1657
+ x="8"
1658
+ y="7"
1659
+ width="6.8362"
1660
+ height="9.13458"
1661
+ rx="2.28119"
1662
+ fill="#F7C330"
1663
+ />
1664
+ </svg>
1665
+ </template>
1666
+ <template v-else-if="event?.icon === 'icon-red-card'">
1667
+ <svg
1668
+ width="23"
1669
+ height="23"
1670
+ viewBox="0 0 23 23"
1671
+ fill="none"
1672
+ xmlns="http://www.w3.org/2000/svg"
1673
+ >
1674
+ <rect width="22.7873" height="22.8364" rx="11.3937" fill="none" />
1675
+ <rect
1676
+ x="8"
1677
+ y="7"
1678
+ width="6.8362"
1679
+ height="9.13458"
1680
+ rx="2.28119"
1681
+ fill="#E5152D"
1682
+ />
1683
+ </svg>
1684
+ </template>
1685
+ <template v-else-if="event?.icon === 'icon-goal'">
1686
+ <svg
1687
+ width="24"
1688
+ height="24"
1689
+ viewBox="0 0 48 48"
1690
+ fill="none"
1691
+ xmlns="http://www.w3.org/2000/svg"
1692
+ >
1693
+ <circle fill="none" cx="24" cy="24" r="24" />
1694
+ <ellipse fill="none" cx="24" cy="24" rx="14.82" ry="14.85" />
1695
+ <path
1696
+ fill="#fff"
1697
+ d="M24.03,36.05c-6.65,0-12.05-5.41-12.05-12.05s5.41-12.05,12.05-12.05,12.05,5.41,12.05,12.05-5.41,12.05-12.05,12.05Zm0-23.1c-6.1,0-11.05,4.96-11.05,11.05s4.96,11.05,11.05,11.05,11.05-4.96,11.05-11.05-4.96-11.05-11.05-11.05Z"
1698
+ />
1699
+ <path
1700
+ fill="#fff"
1701
+ d="M27.22,29.38h-6.35c-.22,0-.41-.14-.48-.35l-1.96-6.06c-.07-.21,0-.43,.18-.56l5.14-3.74c.18-.13,.41-.13,.59,0l5.14,3.74c.17,.13,.25,.35,.18,.56l-1.96,6.06c-.07,.21-.26,.35-.48,.35Zm-5.99-1h5.62l1.74-5.37-4.55-3.32-4.55,3.32,1.74,5.37Z"
1702
+ />
1703
+ <path
1704
+ fill="#fff"
1705
+ d="M24.06,15.71c-.07,0-.13-.01-.2-.04l-4.38-1.87c-.25-.11-.37-.4-.26-.66,.11-.25,.4-.37,.66-.26l4.18,1.78,4.18-1.78c.25-.11,.55,0,.66,.26,.11,.25,0,.55-.26,.66l-4.38,1.87c-.06,.03-.13,.04-.2,.04Z"
1706
+ />
1707
+ <path
1708
+ fill="#fff"
1709
+ d="M12.62,25.37c-.12,0-.23-.04-.33-.12-.21-.18-.23-.5-.05-.71l2.99-3.44-.4-4.54c-.02-.27,.18-.52,.45-.54,.27-.03,.52,.18,.54,.45l.42,4.75c.01,.14-.03,.27-.12,.37l-3.12,3.6c-.1,.11-.24,.17-.38,.17Z"
1710
+ />
1711
+ <path
1712
+ fill="#fff"
1713
+ d="M21.37,35.66c-.17,0-.34-.09-.43-.24l-2.34-3.91-4.43-1.02c-.27-.06-.44-.33-.38-.6s.33-.44,.6-.38l4.64,1.07c.13,.03,.25,.11,.32,.23l2.45,4.09c.14,.24,.06,.54-.17,.69-.08,.05-.17,.07-.26,.07Z"
1714
+ />
1715
+ <path
1716
+ fill="#fff"
1717
+ d="M26.75,35.66c-.09,0-.18-.02-.26-.07-.24-.14-.31-.45-.17-.69l2.44-4.09c.07-.12,.18-.2,.32-.23l4.63-1.07c.27-.06,.54,.11,.6,.38s-.11,.54-.38,.6l-4.43,1.02-2.33,3.91c-.09,.16-.26,.24-.43,.24Z"
1718
+ />
1719
+ <path
1720
+ fill="#fff"
1721
+ d="M35.5,25.37c-.14,0-.28-.06-.38-.17l-3.13-3.6c-.09-.1-.13-.24-.12-.37l.42-4.75c.02-.27,.27-.48,.54-.45,.28,.02,.48,.27,.45,.54l-.4,4.54,2.99,3.44c.18,.21,.16,.52-.05,.71-.09,.08-.21,.12-.33,.12Z"
1722
+ />
1723
+ <path
1724
+ fill="#fff"
1725
+ d="M24.05,19.58c-.28,0-.5-.22-.5-.5v-3.87c0-.28,.22-.5,.5-.5s.5,.22,.5,.5v3.87c0,.28-.22,.5-.5,.5Z"
1726
+ />
1727
+ <path
1728
+ fill="#fff"
1729
+ d="M29.21,23.47c-.18,0-.35-.1-.44-.26-.13-.24-.04-.55,.2-.68l3.17-1.7c.25-.13,.55-.04,.68,.2,.13,.24,.04,.55-.2,.68l-3.17,1.7c-.08,.04-.16,.06-.24,.06Z"
1730
+ />
1731
+ <path
1732
+ fill="#fff"
1733
+ d="M29.2,31.57c-.14,0-.27-.06-.37-.17l-1.96-2.19c-.18-.21-.17-.52,.04-.71,.21-.18,.52-.17,.71,.04l1.96,2.19c.18,.21,.17,.52-.04,.71-.1,.09-.21,.13-.33,.13Z"
1734
+ />
1735
+ <path
1736
+ fill="#fff"
1737
+ d="M18.91,31.57c-.12,0-.24-.04-.33-.13-.21-.18-.22-.5-.04-.71l1.96-2.19c.19-.21,.5-.22,.71-.04,.21,.18,.22,.5,.04,.71l-1.96,2.19c-.1,.11-.24,.17-.37,.17Z"
1738
+ />
1739
+ <path
1740
+ fill="#fff"
1741
+ d="M18.93,23.32c-.07,0-.15-.02-.22-.05l-3.17-1.55c-.25-.12-.35-.42-.23-.67,.12-.25,.42-.35,.67-.23l3.17,1.55c.25,.12,.35,.42,.23,.67-.09,.18-.26,.28-.45,.28Z"
1742
+ />
1743
+ </svg>
1744
+ </template>
1745
+ <template v-else-if="event?.icon === 'icon-change'">
1746
+ <svg
1747
+ width="24"
1748
+ height="24"
1749
+ viewBox="0 0 48 48"
1750
+ fill="none"
1751
+ xmlns="http://www.w3.org/2000/svg"
1752
+ >
1753
+ <circle fill="none" cx="24" cy="24" r="24" />
1754
+ <path
1755
+ fill="#fff"
1756
+ d="M31.62,23.86c-.19,0-.37-.07-.52-.21-.3-.29-.31-.76-.03-1.06l2.89-3.04-2.89-3.04c-.29-.3-.27-.77,.03-1.06,.3-.29,.77-.27,1.06,.03l3.39,3.56c.28,.29,.28,.74,0,1.03l-3.39,3.56c-.15,.15-.34,.23-.54,.23Z"
1757
+ />
1758
+ <path
1759
+ fill="#fff"
1760
+ d="M34.99,20.31H16.37c-.41,0-.75-.34-.75-.75s.34-.75,.75-.75h18.62c.41,0,.75,.34,.75,.75s-.34,.75-.75,.75Z"
1761
+ />
1762
+ <path
1763
+ fill="#fff"
1764
+ d="M16.38,32.75c-.2,0-.4-.08-.54-.23l-3.38-3.56c-.28-.29-.28-.74,0-1.03l3.38-3.56c.28-.3,.76-.31,1.06-.03,.3,.29,.31,.76,.03,1.06l-2.89,3.04,2.89,3.04c.29,.3,.27,.78-.03,1.06-.15,.14-.33,.21-.52,.21Z"
1765
+ />
1766
+ <path
1767
+ fill="#fff"
1768
+ d="M31.62,29.19H13c-.41,0-.75-.34-.75-.75s.34-.75,.75-.75H31.62c.41,0,.75,.34,.75,.75s-.34,.75-.75,.75Z"
1769
+ />
1770
+ </svg>
1771
+ </template>
1772
+ <span v-else :class="event?.icon"></span>
1773
+ </span>
1774
+ </div>
1775
+ </template>
1776
+ <!-- Marcador final (después de los eventos) -->
1777
+ <span
1778
+ class="minute-ball minute-ball-edge minute-ball-center"
1779
+ :style="{ left: getPositionByIndex(timelineMinutes.length - 1) }"
1780
+ >{{ secondHalfEndMinute }}'</span
1781
+ >
1782
+
1783
+ <!-- Indicador de rango verde (arrastrable) -->
1784
+ <div
1785
+ class="range-indicator"
1786
+ :style="{ left: getPositionByIndex(leftHandlePosition), width: rangeWidth }"
1787
+ >
1788
+ <!-- Handle izquierdo -->
1789
+ <div
1790
+ class="handle left"
1791
+ @mousedown="(e) => startDrag('left', e)"
1792
+ @touchstart="(e) => startDrag('left', e)"
1793
+ >
1794
+ <svg
1795
+ width="10"
1796
+ height="6"
1797
+ viewBox="0 0 12 8"
1798
+ style="
1799
+ display: block;
1800
+ margin: 0 auto;
1801
+ position: relative;
1802
+ left: -4.3px;
1803
+ top: -5.5px;
1804
+ "
1805
+ fill="#bfcf4c"
1806
+ xmlns="http://www.w3.org/2000/svg"
1807
+ >
1808
+ <polygon points="6,8 0,0 12,0" />
1809
+ </svg>
1810
+ <div style="flex: 1"></div>
1811
+ <svg
1812
+ width="10"
1813
+ height="6"
1814
+ viewBox="0 0 12 8"
1815
+ style="
1816
+ display: block;
1817
+ margin: 0 auto;
1818
+ position: relative;
1819
+ left: -4.3px;
1820
+ top: 5.5px;
1821
+ transform: rotate(180deg);
1822
+ "
1823
+ fill="#bfcf4c"
1824
+ xmlns="http://www.w3.org/2000/svg"
1825
+ >
1826
+ <polygon points="6,8 0,0 12,0" />
1827
+ </svg>
1828
+ </div>
1829
+ <!-- Bolita izquierda -->
1830
+ <span
1831
+ class="range-dot range-dot-left"
1832
+ @mousedown="(e) => startDrag('left', e)"
1833
+ @touchstart="(e) => startDrag('left', e)"
1834
+ ></span>
1835
+ <!-- Línea de rango -->
1836
+ <div class="range-line"></div>
1837
+ <!-- Bolita derecha -->
1838
+ <span
1839
+ class="range-dot range-dot-right"
1840
+ @mousedown="(e) => startDrag('right', e)"
1841
+ @touchstart="(e) => startDrag('right', e)"
1842
+ ></span>
1843
+ <!-- Handle derecho -->
1844
+ <div
1845
+ class="handle right"
1846
+ @mousedown="(e) => startDrag('right', e)"
1847
+ @touchstart="(e) => startDrag('right', e)"
1848
+ >
1849
+ <svg
1850
+ width="10"
1851
+ height="6"
1852
+ viewBox="0 0 12 8"
1853
+ style="
1854
+ display: block;
1855
+ margin: 0 auto;
1856
+ position: relative;
1857
+ left: -4.3px;
1858
+ top: -5.5px;
1859
+ "
1860
+ fill="#bfcf4c"
1861
+ xmlns="http://www.w3.org/2000/svg"
1862
+ >
1863
+ <polygon points="6,8 0,0 12,0" />
1864
+ </svg>
1865
+ <div style="flex: 1"></div>
1866
+ <svg
1867
+ width="10"
1868
+ height="6"
1869
+ viewBox="0 0 12 8"
1870
+ style="
1871
+ display: block;
1872
+ margin: 0 auto;
1873
+ position: relative;
1874
+ left: -4.3px;
1875
+ top: 5.5px;
1876
+ transform: rotate(180deg);
1877
+ "
1878
+ fill="#bfcf4c"
1879
+ xmlns="http://www.w3.org/2000/svg"
1880
+ >
1881
+ <polygon points="6,8 0,0 12,0" />
1882
+ </svg>
1883
+ </div>
1884
+ </div>
1885
+ </div>
1886
+ </div>
1887
+ </div>
1888
+ <!-- Botones de scroll ocultos -->
1889
+ </div>
1890
+ </div>
1891
+ </template>
1892
+
1893
+ <style scoped>
1894
+ .timeline {
1895
+ border-radius: 8px;
1896
+ font-family: Poppins;
1897
+ margin: 0 auto;
1898
+ transition: width 0.3s ease;
1899
+ overflow: hidden;
1900
+ }
1901
+
1902
+ .timeline-header {
1903
+ color: #fff;
1904
+ display: flex;
1905
+ align-items: center;
1906
+ gap: 8px;
1907
+ margin-bottom: 50px;
1908
+ font-family: Poppins;
1909
+ font-size: 16px;
1910
+ font-weight: 500;
1911
+ font-stretch: normal;
1912
+ font-style: normal;
1913
+ line-height: normal;
1914
+ letter-spacing: normal;
1915
+ text-align: left;
1916
+ }
1917
+
1918
+ .timeline-header span {
1919
+ font-family: Poppins-Medium;
1920
+ font-weight: 500;
1921
+ margin-left: 25px;
1922
+ }
1923
+
1924
+ .timeline-header.small-screen {
1925
+ font-size: 14px;
1926
+ gap: 8px;
1927
+ }
1928
+
1929
+ .timeline-header.small-screen span {
1930
+ font-size: 14px;
1931
+ }
1932
+
1933
+ .timeline-header.small-screen .input-wrapper input {
1934
+ width: 45px;
1935
+ height: 28px;
1936
+ font-size: 12px;
1937
+ }
1938
+
1939
+ .timeline-header.very-small-screen {
1940
+ font-size: 12px;
1941
+ gap: 4px;
1942
+ }
1943
+
1944
+ .timeline-header.very-small-screen span {
1945
+ font-size: 12px;
1946
+ }
1947
+
1948
+ .timeline-header.very-small-screen .input-wrapper input {
1949
+ width: 40px;
1950
+ height: 24px;
1951
+ font-size: 11px;
1952
+ }
1953
+
1954
+ .timeline-header.extra-small-screen {
1955
+ font-size: 11px;
1956
+ gap: 2px;
1957
+ }
1958
+
1959
+ .timeline-header.extra-small-screen span {
1960
+ font-size: 11px;
1961
+ }
1962
+
1963
+ .timeline-header.extra-small-screen .input-wrapper input {
1964
+ width: 35px;
1965
+ height: 22px;
1966
+ font-size: 10px;
1967
+ }
1968
+
1969
+ .timeline-header.extra-small-screen .to-text {
1970
+ margin-left: 10px;
1971
+ margin-top: 1px;
1972
+ }
1973
+
1974
+ .timeline-header .to-text {
1975
+ margin-left: 7px;
1976
+ margin-right: 7px;
1977
+ color: #fff;
1978
+ font-family: Poppins-Medium;
1979
+ font-size: 16px;
1980
+ font-weight: 500;
1981
+ font-stretch: normal;
1982
+ font-style: normal;
1983
+ line-height: normal;
1984
+ letter-spacing: normal;
1985
+ text-align: left;
1986
+ }
1987
+
1988
+ .timeline-header.very-small-screen .to-text {
1989
+ margin-left: 25px;
1990
+ margin-top: 2px;
1991
+ font-size: 12px;
1992
+ }
1993
+
1994
+ .timeline-header.extra-small-screen .to-text {
1995
+ margin-left: 30px;
1996
+ margin-top: 1px;
1997
+ font-size: 11px;
1998
+ }
1999
+
2000
+ .input-wrapper {
2001
+ position: relative;
2002
+ display: flex;
2003
+ align-items: center;
2004
+ }
2005
+
2006
+ .input-container {
2007
+ position: relative;
2008
+ display: flex;
2009
+ align-items: center;
2010
+ width: 85px;
2011
+ height: 31px;
2012
+ border-radius: 4px;
2013
+ background: transparent;
2014
+ }
2015
+
2016
+ .input-label {
2017
+ position: absolute;
2018
+ left: -20px;
2019
+ color: rgba(255, 255, 255, 0.7);
2020
+ font-family: Poppins-Light !important;
2021
+ font-size: 13px;
2022
+ font-weight: 500;
2023
+ pointer-events: none;
2024
+ }
2025
+
2026
+ .timeline-header input {
2027
+ width: 100%;
2028
+ height: 100%;
2029
+ border: none;
2030
+ background: transparent;
2031
+ color: rgba(255, 255, 255, 0.7);
2032
+ text-align: center;
2033
+ font-family: Poppins-Medium;
2034
+ font-size: 13px;
2035
+ font-weight: 500;
2036
+ padding-left: 25px;
2037
+ padding-right: 25px;
2038
+ -moz-appearance: textfield;
2039
+ outline: none;
2040
+ border: solid 1px #505a62;
2041
+ }
2042
+
2043
+ .timeline-header input:focus {
2044
+ outline: none;
2045
+ border: solid 1px #505a62;
2046
+ box-shadow: none;
2047
+ -webkit-box-shadow: none;
2048
+ -moz-box-shadow: none;
2049
+ }
2050
+
2051
+ .timeline-header input::-webkit-inner-spin-button,
2052
+ .timeline-header input::-webkit-outer-spin-button {
2053
+ -webkit-appearance: none;
2054
+ margin: 0;
2055
+ }
2056
+
2057
+ .input-arrows {
2058
+ position: absolute;
2059
+ right: 4px;
2060
+ display: flex;
2061
+ flex-direction: column;
2062
+ gap: 2px;
2063
+ z-index: 1;
2064
+ }
2065
+
2066
+ .input-arrows button {
2067
+ background: none;
2068
+ border: none;
2069
+ padding: 0;
2070
+ cursor: pointer;
2071
+ color: #bfcf4c;
2072
+ display: flex;
2073
+ align-items: center;
2074
+ justify-content: center;
2075
+ width: 16px;
2076
+ height: 10px;
2077
+ transition: color 0.2s ease;
2078
+ }
2079
+
2080
+ .input-arrows button:hover {
2081
+ color: #d4e35c;
2082
+ }
2083
+
2084
+ .input-arrows button svg {
2085
+ width: 10px;
2086
+ height: 6px;
2087
+ }
2088
+
2089
+ .timeline-header.small-screen .input-container {
2090
+ width: 65px;
2091
+ height: 28px;
2092
+ }
2093
+
2094
+ .timeline-header.small-screen .input-label {
2095
+ font-size: 12px;
2096
+ left: 6px;
2097
+ }
2098
+
2099
+ .timeline-header.small-screen input {
2100
+ font-size: 12px;
2101
+ padding-left: 20px;
2102
+ padding-right: 20px;
2103
+ }
2104
+
2105
+ .timeline-header.very-small-screen .input-container {
2106
+ width: 60px;
2107
+ height: 24px;
2108
+ }
2109
+
2110
+ .timeline-header.very-small-screen .input-label {
2111
+ font-size: 11px;
2112
+ left: 5px;
2113
+ }
2114
+
2115
+ .timeline-header.very-small-screen input {
2116
+ font-size: 11px;
2117
+ padding-left: 18px;
2118
+ padding-right: 18px;
2119
+ }
2120
+
2121
+ .timeline-header.extra-small-screen .input-container {
2122
+ width: 70px;
2123
+ min-width: 65px;
2124
+ height: 26px;
2125
+ }
2126
+
2127
+ .timeline-header.extra-small-screen .input-label {
2128
+ font-size: 11px;
2129
+ left: 4px;
2130
+ }
2131
+
2132
+ .timeline-header.extra-small-screen input {
2133
+ font-size: 12px;
2134
+ min-width: 40px;
2135
+ padding-left: 12px;
2136
+ padding-right: 12px;
2137
+ }
2138
+
2139
+ .timeline-container {
2140
+ position: relative;
2141
+ display: flex;
2142
+ align-items: center;
2143
+ justify-content: center; /* Centra horizontalmente */
2144
+ width: 100%;
2145
+ overflow: hidden;
2146
+ height: 120px;
2147
+ box-sizing: border-box;
2148
+ }
2149
+
2150
+ .timeline-scroll {
2151
+ overflow-x: auto;
2152
+ overflow-y: hidden;
2153
+ -webkit-overflow-scrolling: touch;
2154
+ scrollbar-width: none;
2155
+ -ms-overflow-style: none;
2156
+ width: 100%;
2157
+ height: 100%;
2158
+ margin: 0 auto;
2159
+ box-sizing: border-box;
2160
+ }
2161
+
2162
+ .timeline-bar {
2163
+ position: relative;
2164
+ height: 60px;
2165
+ margin: 0 auto;
2166
+ margin-left: 60px;
2167
+ margin-top: 28px;
2168
+ flex-shrink: 0;
2169
+ transition: margin-left 0.3s ease;
2170
+ box-sizing: border-box;
2171
+ display: flex;
2172
+ justify-content: space-between;
2173
+ }
2174
+
2175
+ .timeline-bar.has-scroll {
2176
+ margin-left: 40px;
2177
+ }
2178
+
2179
+ .scroll-arrow {
2180
+ position: absolute;
2181
+ top: 85%;
2182
+ transform: translateY(-50%);
2183
+ background: rgba(13, 29, 41, 0.8);
2184
+ border: 1px solid #4b80ae;
2185
+ border-radius: 50%;
2186
+ width: 32px;
2187
+ height: 32px;
2188
+ display: flex;
2189
+ align-items: center;
2190
+ justify-content: center;
2191
+ cursor: pointer;
2192
+ color: #fff;
2193
+ z-index: 10;
2194
+ transition: all 0.2s ease;
2195
+ margin: 0;
2196
+ opacity: 1;
2197
+ }
2198
+
2199
+ .scroll-left {
2200
+ left: 0;
2201
+ }
2202
+
2203
+ .scroll-right {
2204
+ right: 0;
2205
+ }
2206
+
2207
+ .scroll-arrow:hover {
2208
+ background: rgba(13, 29, 41, 0.9);
2209
+ border-color: #5b90be;
2210
+ }
2211
+
2212
+ .line {
2213
+ position: absolute;
2214
+ top: 50%;
2215
+ left: 48%;
2216
+ width: 98%;
2217
+ height: 2px;
2218
+ background: #3a6081;
2219
+ transform: translate(-50%, -50%);
2220
+ border-radius: 2px;
2221
+ }
2222
+ .event {
2223
+ position: absolute;
2224
+ left: 0;
2225
+ width: 24px;
2226
+ display: flex;
2227
+ flex-direction: column;
2228
+ align-items: center;
2229
+ z-index: 2;
2230
+ margin-top: 30px;
2231
+ transition: all 0.3s ease;
2232
+ }
2233
+ .event-first-half {
2234
+ opacity: 1;
2235
+ }
2236
+ .event-second-half {
2237
+ opacity: 1;
2238
+ }
2239
+ .minute-ball-center {
2240
+ position: absolute;
2241
+ top: 50%;
2242
+ left: 50%;
2243
+ transform: translate(-50%, -50%);
2244
+ z-index: 2;
2245
+ }
2246
+ .event-icon-top {
2247
+ position: absolute;
2248
+ left: 50%;
2249
+ top: calc(50% - 11px);
2250
+ transform: translate(-50%, -100%);
2251
+ }
2252
+ .event-icon-bottom {
2253
+ position: absolute;
2254
+ left: 50%;
2255
+ top: calc(50% + 11px);
2256
+ transform: translate(-50%, 0);
2257
+ }
2258
+ .minute-ball {
2259
+ width: 20px;
2260
+ height: 20px;
2261
+ border-radius: 33.3px;
2262
+ border: solid 1px #4b80ae;
2263
+ background-color: #0d1d29;
2264
+ color: #fff;
2265
+ display: flex;
2266
+ font-family: poppins-Medium;
2267
+ align-items: center;
2268
+ justify-content: center;
2269
+ font-size: 10px;
2270
+ font-weight: bold;
2271
+ margin: 0 auto;
2272
+ transition: all 0.3s ease;
2273
+ }
2274
+ /* Ejemplo de iconos, reemplaza por tus propios SVG o clases */
2275
+ .icon-yellow-card {
2276
+ width: 16px;
2277
+ height: 16px;
2278
+ background: yellow;
2279
+ border-radius: 3px;
2280
+ display: inline-block;
2281
+ border: 1px solid #aaa;
2282
+ }
2283
+ .icon-goal {
2284
+ width: 16px;
2285
+ height: 16px;
2286
+ background: #fff;
2287
+ border-radius: 50%;
2288
+ display: inline-block;
2289
+ border: 2px solid #0af;
2290
+ }
2291
+ .icon-red-card {
2292
+ width: 16px;
2293
+ height: 16px;
2294
+ background: red;
2295
+ border-radius: 3px;
2296
+ display: inline-block;
2297
+ border: 1px solid #aaa;
2298
+ }
2299
+ .icon-var {
2300
+ width: 16px;
2301
+ height: 16px;
2302
+ background: #0af;
2303
+ border-radius: 3px;
2304
+ display: inline-block;
2305
+ border: 1px solid #fff;
2306
+ }
2307
+ .icon-change {
2308
+ width: 16px;
2309
+ height: 16px;
2310
+ background: #aaa;
2311
+ border-radius: 50%;
2312
+ display: inline-block;
2313
+ border: 2px dashed #fff;
2314
+ }
2315
+ .range-indicator {
2316
+ position: absolute;
2317
+ top: 34%;
2318
+ height: 20px;
2319
+ cursor: pointer;
2320
+ z-index: 1;
2321
+ display: flex;
2322
+ align-items: center;
2323
+ left: 12px;
2324
+ right: 12px;
2325
+ }
2326
+ .handle {
2327
+ width: 1px;
2328
+ height: 60px;
2329
+ background: #bfcf4c;
2330
+ cursor: pointer;
2331
+ margin: 0 2px;
2332
+ display: flex;
2333
+ flex-direction: column;
2334
+ align-items: center;
2335
+ justify-content: space-between;
2336
+ padding: 2px 0;
2337
+ touch-action: none;
2338
+ user-select: none;
2339
+ transition: background-color 0.2s ease;
2340
+ }
2341
+
2342
+ .handle:hover {
2343
+ background: #d4e35c;
2344
+ }
2345
+
2346
+ .range-line {
2347
+ flex: 1;
2348
+ height: 2px;
2349
+ background: #bfcf4c;
2350
+ margin: 0 -2px;
2351
+ }
2352
+ .minute-ball-edge {
2353
+ z-index: 4;
2354
+ border: none;
2355
+ }
2356
+ .minute-ball-initial {
2357
+ z-index: 2;
2358
+ border: 1px solid #4b80ae;
2359
+ background-color: #0d1d29;
2360
+ color: #fff;
2361
+ font-weight: bold;
2362
+ font-size: 10px;
2363
+ }
2364
+ .minute-ball:not(.minute-ball-edge) {
2365
+ border: solid 1px #4b80ae;
2366
+ }
2367
+ .range-dot {
2368
+ position: absolute;
2369
+ top: 50%;
2370
+ width: 10px;
2371
+ height: 10px;
2372
+ border-radius: 33.3px;
2373
+ border: solid 1px #bfcf4c;
2374
+ background-color: #bfcf4c;
2375
+ transform: translateY(-50%);
2376
+ z-index: 10;
2377
+ cursor: pointer;
2378
+ touch-action: none;
2379
+ user-select: none;
2380
+ transition: all 0.2s ease;
2381
+ }
2382
+
2383
+ .range-dot:hover {
2384
+ background: #d4e35c;
2385
+ border-color: #d4e35c;
2386
+ transform: translateY(-50%) scale(1.1);
2387
+ }
2388
+
2389
+ .range-dot-left {
2390
+ left: 0;
2391
+ margin-left: 3px;
2392
+ transform: translate(-50%, -50%);
2393
+ }
2394
+
2395
+ .range-dot-left:hover {
2396
+ background: #d4e35c;
2397
+ border-color: #d4e35c;
2398
+ transform: translate(-50%, -50%) scale(1.1);
2399
+ }
2400
+
2401
+ .range-dot-right {
2402
+ right: 0;
2403
+ margin-right: 3px;
2404
+ transform: translate(50%, -50%);
2405
+ }
2406
+
2407
+ .range-dot-right:hover {
2408
+ background: #d4e35c;
2409
+ border-color: #d4e35c;
2410
+ transform: translate(50%, -50%) scale(1.1);
2411
+ }
2412
+
2413
+ /* Estilos para feedback visual durante el arrastre */
2414
+ .timeline.is-dragging {
2415
+ cursor: grabbing;
2416
+ user-select: none;
2417
+ }
2418
+
2419
+ .timeline.is-dragging * {
2420
+ pointer-events: none;
2421
+ }
2422
+
2423
+ .timeline.is-dragging .handle,
2424
+ .timeline.is-dragging .range-dot {
2425
+ pointer-events: auto;
2426
+ background: #d4e35c;
2427
+ border-color: #d4e35c;
2428
+ cursor: grabbing;
2429
+ }
2430
+
2431
+ .timeline.is-dragging .range-line {
2432
+ background: #d4e35c;
2433
+ }
2434
+
2435
+ .team-circle {
2436
+ position: absolute;
2437
+ left: -27px;
2438
+ width: 20px;
2439
+ height: 20px;
2440
+ border-radius: 50%;
2441
+ background: #0d1d29;
2442
+ border: 1px solid #4b80ae;
2443
+ display: flex;
2444
+ align-items: center;
2445
+ justify-content: center;
2446
+ z-index: 2;
2447
+ }
2448
+
2449
+ .team-circle img {
2450
+ width: 14px;
2451
+ height: 14px;
2452
+ object-fit: contain;
2453
+ }
2454
+
2455
+ .team-circle-top {
2456
+ top: -5px;
2457
+ }
2458
+
2459
+ .team-circle-bottom {
2460
+ bottom: -5px;
2461
+ }
2462
+
2463
+ .time-select {
2464
+ width: 150px;
2465
+ height: 31px;
2466
+ border-radius: 4px;
2467
+ border: solid 1px #505a62;
2468
+ background: transparent;
2469
+ color: rgba(255, 255, 255, 0.7);
2470
+ text-align: center;
2471
+ font-family: Poppins-Medium;
2472
+ font-size: 13px;
2473
+ font-weight: 500;
2474
+ font-stretch: normal;
2475
+ font-style: normal;
2476
+ line-height: 1.5;
2477
+ letter-spacing: normal;
2478
+ margin-right: 8px;
2479
+ cursor: pointer;
2480
+ appearance: none;
2481
+ -webkit-appearance: none;
2482
+ -moz-appearance: none;
2483
+ background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23bfcf4c' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
2484
+ background-repeat: no-repeat;
2485
+ background-position: right 8px center;
2486
+ background-size: 12px;
2487
+ padding-right: 20px;
2488
+ outline: none;
2489
+ }
2490
+ .time-select:focus {
2491
+ outline: none;
2492
+ border: solid 1px #505a62;
2493
+ box-shadow: none;
2494
+ -webkit-box-shadow: none;
2495
+ -moz-box-shadow: none;
2496
+ }
2497
+
2498
+ .time-select option {
2499
+ background-color: #0d1d29;
2500
+ color: #fff;
2501
+ }
2502
+
2503
+ .timeline-header.small-screen .time-select {
2504
+ width: 130px;
2505
+ height: 28px;
2506
+ font-size: 12px;
2507
+ }
2508
+
2509
+ .timeline-header.very-small-screen .time-select {
2510
+ width: 110px;
2511
+ height: 24px;
2512
+ font-size: 11px;
2513
+ margin-right: 4px;
2514
+ }
2515
+
2516
+ .timeline-header.extra-small-screen .time-select {
2517
+ width: 100px;
2518
+ height: 22px;
2519
+ font-size: 10px;
2520
+ margin-right: 2px;
2521
+ }
2522
+
2523
+ .timeline-header.extra-small-screen .time-select option {
2524
+ font-size: 10px;
2525
+ }
2526
+
2527
+ .timeline-line {
2528
+ position: relative;
2529
+ height: 60px;
2530
+ width: 100%;
2531
+ }
2532
+
2533
+ /* Eliminar los estilos de las líneas separadas */
2534
+ .timeline-line.first-half,
2535
+ .timeline-line.second-half {
2536
+ border: none;
2537
+ }
2538
+
2539
+ /* Eliminar los estilos de los marcadores de minutos */
2540
+ .minute-marker {
2541
+ display: none;
2542
+ }
2543
+
2544
+ .time-separator {
2545
+ position: absolute;
2546
+ top: 0;
2547
+ bottom: 0;
2548
+ width: 2px;
2549
+ background: rgba(191, 207, 76, 0.3);
2550
+ z-index: 1;
2551
+ }
2552
+
2553
+ .time-separator::before {
2554
+ content: '';
2555
+ position: absolute;
2556
+ top: 50%;
2557
+ left: 50%;
2558
+ transform: translate(-50%, -50%);
2559
+ width: 8px;
2560
+ height: 8px;
2561
+ border-radius: 50%;
2562
+ background: #bfcf4c;
2563
+ opacity: 0.5;
2564
+ }
2565
+
2566
+ /* Estilos para la escala de minutos */
2567
+ .minute-scale {
2568
+ position: absolute;
2569
+ top: 50%;
2570
+ transform: translate(-50%, -50%);
2571
+ z-index: 1;
2572
+ pointer-events: none;
2573
+ }
2574
+
2575
+ .minute-label {
2576
+ font-size: 8px;
2577
+ color: rgba(255, 255, 255, 0.5);
2578
+ font-family: Poppins;
2579
+ font-weight: 400;
2580
+ white-space: nowrap;
2581
+ background: rgba(13, 29, 41, 0.8);
2582
+ padding: 1px 3px;
2583
+ border-radius: 2px;
2584
+ border: 1px solid rgba(75, 128, 174, 0.3);
2585
+ }
2586
+
2587
+ .timeline-header.responsive-header {
2588
+ flex-wrap: wrap;
2589
+ flex-direction: row;
2590
+ gap: 8px;
2591
+ }
2592
+ .header-row {
2593
+ display: flex;
2594
+ align-items: center;
2595
+ gap: 8px;
2596
+ }
2597
+
2598
+ .timeline-header.mobile-column {
2599
+ flex-direction: column !important;
2600
+ align-items: center !important;
2601
+ gap: 10px !important;
2602
+ width: 100% !important;
2603
+ }
2604
+ .timeline-header.mobile-column .header-title {
2605
+ text-align: center !important;
2606
+ font-size: 16px !important;
2607
+ margin: 0 !important;
2608
+ width: 100% !important;
2609
+ }
2610
+ .timeline-header.mobile-column .header-row {
2611
+ flex-direction: row !important;
2612
+ align-items: center !important;
2613
+ width: 100% !important;
2614
+ gap: 8px !important;
2615
+ justify-content: space-between !important;
2616
+ padding: 0 10px !important;
2617
+ }
2618
+ .timeline-header.mobile-column .to-text {
2619
+ margin: 0 !important;
2620
+ font-size: 15px !important;
2621
+ text-align: center !important;
2622
+ flex-shrink: 0 !important;
2623
+ }
2624
+ .timeline-header.mobile-column .input-container {
2625
+ width: 45% !important;
2626
+ min-width: 80px !important;
2627
+ height: 34px !important;
2628
+ position: relative !important;
2629
+ display: flex !important;
2630
+ align-items: center !important;
2631
+ }
2632
+ .timeline-header.mobile-column input {
2633
+ font-size: 15px !important;
2634
+ min-width: 60px !important;
2635
+ height: 34px !important;
2636
+ padding-left: 25px !important;
2637
+ padding-right: 10px !important;
2638
+ width: 100% !important;
2639
+ }
2640
+ .timeline-header.mobile-column .input-label {
2641
+ font-size: 13px !important;
2642
+ left: -20px !important;
2643
+ position: absolute !important;
2644
+ top: 50% !important;
2645
+ transform: translateY(-50%) !important;
2646
+ pointer-events: none !important;
2647
+ }
2648
+ .timeline-header.mobile-column .time-select {
2649
+ width: 45% !important;
2650
+ min-width: 120px !important;
2651
+ max-width: none !important;
2652
+ height: 34px !important;
2653
+ font-size: 15px !important;
2654
+ margin: 0 !important;
2655
+ display: flex !important;
2656
+ align-items: center !important;
2657
+ justify-content: center !important;
2658
+ }
2659
+ .timeline-header.mobile-column .input-wrapper {
2660
+ width: 45% !important;
2661
+ display: flex !important;
2662
+ justify-content: center !important;
2663
+ }
2664
+ @media (max-width: 470px) {
2665
+ .timeline-header.responsive-header {
2666
+ flex-direction: column;
2667
+ align-items: flex-start;
2668
+ gap: 6px;
2669
+ }
2670
+ .header-row {
2671
+ flex-direction: row;
2672
+ width: 100%;
2673
+ justify-content: flex-start;
2674
+ gap: 6px;
2675
+ }
2676
+ }
2677
+ @media (max-width: 420px) {
2678
+ .timeline-header.responsive-header {
2679
+ flex-direction: column;
2680
+ align-items: flex-start;
2681
+ gap: 4px;
2682
+ }
2683
+ .header-row {
2684
+ flex-direction: row;
2685
+ width: 100%;
2686
+ justify-content: flex-start;
2687
+ gap: 4px;
2688
+ }
2689
+ }
2690
+ @media (max-width: 370px) {
2691
+ .timeline-header.responsive-header {
2692
+ gap: 2px;
2693
+ }
2694
+ .header-row {
2695
+ gap: 2px;
2696
+ }
2697
+ }
2698
+ @media (max-width: 500px) {
2699
+ .timeline-header.responsive-header {
2700
+ flex-direction: column;
2701
+ align-items: center;
2702
+ gap: 10px;
2703
+ width: 100%;
2704
+ }
2705
+ .header-row {
2706
+ flex-direction: column;
2707
+ align-items: center;
2708
+ width: 100%;
2709
+ gap: 8px;
2710
+ }
2711
+ .timeline-header .to-text {
2712
+ margin: 0 0 0 0;
2713
+ font-size: 15px;
2714
+ text-align: center;
2715
+ }
2716
+ .input-wrapper {
2717
+ width: 100%;
2718
+ display: flex;
2719
+ justify-content: center;
2720
+ }
2721
+ .input-container {
2722
+ width: 90px !important;
2723
+ min-width: 80px;
2724
+ height: 34px !important;
2725
+ font-size: 15px;
2726
+ }
2727
+ .timeline-header input {
2728
+ font-size: 15px !important;
2729
+ min-width: 60px;
2730
+ height: 34px;
2731
+ padding-left: 10px;
2732
+ padding-right: 10px;
2733
+ }
2734
+ .timeline-header .input-label {
2735
+ font-size: 13px !important;
2736
+ left: 2px;
2737
+ }
2738
+ .time-select {
2739
+ width: 100% !important;
2740
+ min-width: 120px;
2741
+ max-width: 180px;
2742
+ height: 34px !important;
2743
+ font-size: 15px !important;
2744
+ margin: 0 auto 0 auto;
2745
+ display: block;
2746
+ }
2747
+ }
2748
+
2749
+ .timeline-header.small-screen .input-container {
2750
+ width: 80px;
2751
+ height: 30px;
2752
+ }
2753
+ .timeline-header.small-screen .input-label {
2754
+ font-size: 13px;
2755
+ left: 6px;
2756
+ }
2757
+ .timeline-header.small-screen input {
2758
+ font-size: 13px;
2759
+ min-width: 50px;
2760
+ height: 30px;
2761
+ padding-left: 10px;
2762
+ padding-right: 10px;
2763
+ }
2764
+ .timeline-header.small-screen .time-select {
2765
+ width: 120px;
2766
+ height: 30px;
2767
+ font-size: 13px;
2768
+ }
2769
+
2770
+ .timeline-header.very-small-screen .input-container {
2771
+ width: 90px;
2772
+ height: 32px;
2773
+ }
2774
+ .timeline-header.very-small-screen .input-label {
2775
+ font-size: 14px;
2776
+ left: 5px;
2777
+ }
2778
+ .timeline-header.very-small-screen input {
2779
+ font-size: 14px;
2780
+ min-width: 55px;
2781
+ height: 32px;
2782
+ padding-left: 10px;
2783
+ padding-right: 10px;
2784
+ }
2785
+ .timeline-header.very-small-screen .time-select {
2786
+ width: 130px;
2787
+ height: 32px;
2788
+ font-size: 14px;
2789
+ }
2790
+
2791
+ .timeline-header.extra-small-screen .input-container {
2792
+ width: 100px;
2793
+ min-width: 80px;
2794
+ height: 36px;
2795
+ }
2796
+ .timeline-header.extra-small-screen .input-label {
2797
+ font-size: 15px;
2798
+ left: 4px;
2799
+ }
2800
+ .timeline-header.extra-small-screen input {
2801
+ font-size: 15px;
2802
+ min-width: 60px;
2803
+ height: 36px;
2804
+ padding-left: 8px;
2805
+ padding-right: 8px;
2806
+ }
2807
+ .timeline-header.extra-small-screen .time-select {
2808
+ width: 140px;
2809
+ height: 36px;
2810
+ font-size: 15px;
2811
+ }
2812
+
2813
+ .timeline-header.mobile-column {
2814
+ flex-direction: column;
2815
+ align-items: center;
2816
+ gap: 10px;
2817
+ width: 100%;
2818
+ }
2819
+ .timeline-header.mobile-column .header-row {
2820
+ flex-direction: column;
2821
+ align-items: center;
2822
+ width: 100%;
2823
+ gap: 8px;
2824
+ }
2825
+ .timeline-header.mobile-column .to-text {
2826
+ margin: 0;
2827
+ font-size: 15px;
2828
+ text-align: center;
2829
+ }
2830
+ .timeline-header.mobile-column .input-container {
2831
+ width: 50% !important;
2832
+ min-width: 80px !important;
2833
+ height: 34px !important;
2834
+ }
2835
+ .timeline-header.mobile-column input {
2836
+ font-size: 15px !important;
2837
+ min-width: 60px !important;
2838
+ height: 34px !important;
2839
+ padding-left: 10px !important;
2840
+ padding-right: 10px !important;
2841
+ }
2842
+ .timeline-header.mobile-column .input-label {
2843
+ font-size: 13px !important;
2844
+ left: 2px !important;
2845
+ }
2846
+ .timeline-header.mobile-column .time-select {
2847
+ width: 50% !important;
2848
+ min-width: 120px !important;
2849
+ max-width: 180px !important;
2850
+ height: 34px !important;
2851
+ font-size: 15px !important;
2852
+ margin: 0 !important;
2853
+ }
2854
+ .timeline-header.mobile-column .input-wrapper {
2855
+ width: 50% !important;
2856
+ display: flex !important;
2857
+ justify-content: center !important;
2858
+ }
2859
+ .timeline-header.mobile-column input {
2860
+ font-size: 15px !important;
2861
+ min-width: 60px !important;
2862
+ height: 34px !important;
2863
+ padding-left: 35px !important;
2864
+ padding-right: 10px !important;
2865
+ width: 100% !important;
2866
+ outline: none !important;
2867
+ }
2868
+ .timeline-header.mobile-column input:focus {
2869
+ outline: none !important;
2870
+ border: solid 1px #505a62 !important;
2871
+ box-shadow: none !important;
2872
+ -webkit-box-shadow: none !important;
2873
+ -moz-box-shadow: none !important;
2874
+ }
2875
+ .timeline-header.mobile-column .input-label {
2876
+ font-size: 13px !important;
2877
+ left: -18px !important;
2878
+ position: absolute !important;
2879
+ top: 50% !important;
2880
+ transform: translateY(-50%) !important;
2881
+ pointer-events: none !important;
2882
+ }
2883
+ .timeline-header.mobile-column .time-select:focus {
2884
+ outline: none !important;
2885
+ border: solid 1px #505a62 !important;
2886
+ box-shadow: none !important;
2887
+ -webkit-box-shadow: none !important;
2888
+ -moz-box-shadow: none !important;
2889
+ }
2890
+
2891
+ /* Estilos para pantallas menores a 800px */
2892
+ .timeline-header.tablet-layout {
2893
+ flex-direction: column !important;
2894
+ align-items: center !important;
2895
+ gap: 15px !important;
2896
+ width: 100% !important;
2897
+ }
2898
+
2899
+ .timeline-header.tablet-layout .header-title {
2900
+ text-align: center !important;
2901
+ font-size: 18px !important;
2902
+ margin: 0 !important;
2903
+ width: 100% !important;
2904
+ order: 1 !important;
2905
+ }
2906
+
2907
+ .timeline-header.tablet-layout .header-row {
2908
+ flex-direction: row !important;
2909
+ align-items: center !important;
2910
+ width: 100% !important;
2911
+ gap: 12px !important;
2912
+ justify-content: center !important;
2913
+ order: 2 !important;
2914
+ flex-wrap: wrap !important;
2915
+ }
2916
+
2917
+ .timeline-header.tablet-layout .to-text {
2918
+ margin: 0 !important;
2919
+ font-size: 16px !important;
2920
+ text-align: center !important;
2921
+ flex-shrink: 0 !important;
2922
+ }
2923
+
2924
+ .timeline-header.tablet-layout .input-container {
2925
+ width: 90px !important;
2926
+ min-width: 80px !important;
2927
+ height: 36px !important;
2928
+ position: relative !important;
2929
+ display: flex !important;
2930
+ align-items: center !important;
2931
+ }
2932
+
2933
+ .timeline-header.tablet-layout input {
2934
+ font-size: 16px !important;
2935
+ min-width: 60px !important;
2936
+ height: 36px !important;
2937
+ padding-left: 25px !important;
2938
+ padding-right: 10px !important;
2939
+ width: 100% !important;
2940
+ }
2941
+
2942
+ .timeline-header.tablet-layout .input-label {
2943
+ font-size: 14px !important;
2944
+ left: -20px !important;
2945
+ position: absolute !important;
2946
+ top: 50% !important;
2947
+ transform: translateY(-50%) !important;
2948
+ pointer-events: none !important;
2949
+ }
2950
+
2951
+ .timeline-header.tablet-layout .time-select {
2952
+ width: 160px !important;
2953
+ min-width: 140px !important;
2954
+ max-width: none !important;
2955
+ height: 36px !important;
2956
+ font-size: 16px !important;
2957
+ margin: 0 !important;
2958
+ display: flex !important;
2959
+ align-items: center !important;
2960
+ justify-content: center !important;
2961
+ }
2962
+
2963
+ .timeline-header.tablet-layout .input-wrapper {
2964
+ width: auto !important;
2965
+ display: flex !important;
2966
+ justify-content: center !important;
2967
+ }
2968
+
2969
+ .timeline-header.tablet-layout input:focus {
2970
+ outline: none !important;
2971
+ border: solid 1px #505a62 !important;
2972
+ box-shadow: none !important;
2973
+ -webkit-box-shadow: none !important;
2974
+ -moz-box-shadow: none !important;
2975
+ }
2976
+
2977
+ .timeline-header.tablet-layout .time-select:focus {
2978
+ outline: none !important;
2979
+ border: solid 1px #505a62 !important;
2980
+ box-shadow: none !important;
2981
+ -webkit-box-shadow: none !important;
2982
+ -moz-box-shadow: none !important;
2983
+ }
2984
+
2985
+ /* Estilos para pantallas menores a 600px */
2986
+ .timeline-header.mobile-layout {
2987
+ flex-direction: column !important;
2988
+ align-items: center !important;
2989
+ gap: 12px !important;
2990
+ width: 100% !important;
2991
+ }
2992
+
2993
+ .timeline-header.mobile-layout .header-title {
2994
+ text-align: center !important;
2995
+ font-size: 18px !important;
2996
+ margin: 0 !important;
2997
+ width: 100% !important;
2998
+ order: 1 !important;
2999
+ }
3000
+
3001
+ .timeline-header.mobile-layout .controls-row {
3002
+ flex-direction: column !important;
3003
+ gap: 8px !important;
3004
+ align-items: center !important;
3005
+ order: 2 !important;
3006
+ }
3007
+
3008
+ .timeline-header.mobile-layout .controls-row .time-select:first-of-type,
3009
+ .timeline-header.mobile-layout .controls-row .input-wrapper:first-of-type {
3010
+ order: 1 !important;
3011
+ }
3012
+
3013
+ .timeline-header.mobile-layout .controls-row .to-text {
3014
+ order: 2 !important;
3015
+ margin: 0 !important;
3016
+ font-size: 16px !important;
3017
+ text-align: center !important;
3018
+ flex-shrink: 0 !important;
3019
+ width: 100% !important;
3020
+ }
3021
+
3022
+ .timeline-header.mobile-layout .controls-row .time-select:last-of-type,
3023
+ .timeline-header.mobile-layout .controls-row .input-wrapper:last-of-type {
3024
+ order: 3 !important;
3025
+ }
3026
+
3027
+ .timeline-header.mobile-layout .header-row:first-of-type {
3028
+ flex-direction: row !important;
3029
+ align-items: center !important;
3030
+ width: 100% !important;
3031
+ gap: 12px !important;
3032
+ justify-content: center !important;
3033
+ order: 2 !important;
3034
+ }
3035
+
3036
+ .timeline-header.mobile-layout .header-row:last-of-type {
3037
+ flex-direction: row !important;
3038
+ align-items: center !important;
3039
+ width: 100% !important;
3040
+ gap: 12px !important;
3041
+ justify-content: center !important;
3042
+ order: 3 !important;
3043
+ }
3044
+
3045
+ .timeline-header.mobile-layout .to-text {
3046
+ margin: 0 !important;
3047
+ font-size: 16px !important;
3048
+ text-align: center !important;
3049
+ flex-shrink: 0 !important;
3050
+ }
3051
+
3052
+ .timeline-header.mobile-layout .input-container {
3053
+ width: 90px !important;
3054
+ min-width: 80px !important;
3055
+ height: 36px !important;
3056
+ position: relative !important;
3057
+ display: flex !important;
3058
+ align-items: center !important;
3059
+ }
3060
+
3061
+ .timeline-header.mobile-layout input {
3062
+ font-size: 16px !important;
3063
+ min-width: 60px !important;
3064
+ height: 36px !important;
3065
+ padding-left: 25px !important;
3066
+ padding-right: 10px !important;
3067
+ width: 100% !important;
3068
+ }
3069
+
3070
+ .timeline-header.mobile-layout .input-label {
3071
+ font-size: 14px !important;
3072
+ left: -20px !important;
3073
+ position: absolute !important;
3074
+ top: 50% !important;
3075
+ transform: translateY(-50%) !important;
3076
+ pointer-events: none !important;
3077
+ }
3078
+
3079
+ .timeline-header.mobile-layout .time-select {
3080
+ width: 160px !important;
3081
+ min-width: 140px !important;
3082
+ max-width: none !important;
3083
+ height: 36px !important;
3084
+ font-size: 16px !important;
3085
+ margin: 0 !important;
3086
+ display: flex !important;
3087
+ align-items: center !important;
3088
+ justify-content: center !important;
3089
+ }
3090
+
3091
+ .timeline-header.mobile-layout .input-wrapper {
3092
+ width: auto !important;
3093
+ display: flex !important;
3094
+ justify-content: center !important;
3095
+ }
3096
+
3097
+ .timeline-header.mobile-layout input:focus {
3098
+ outline: none !important;
3099
+ border: solid 1px #505a62 !important;
3100
+ box-shadow: none !important;
3101
+ -webkit-box-shadow: none !important;
3102
+ -moz-box-shadow: none !important;
3103
+ }
3104
+
3105
+ .timeline-header.mobile-layout .time-select:focus {
3106
+ outline: none !important;
3107
+ border: solid 1px #505a62 !important;
3108
+ box-shadow: none !important;
3109
+ -webkit-box-shadow: none !important;
3110
+ -moz-box-shadow: none !important;
3111
+ }
3112
+
3113
+ .range-indicator,
3114
+ .handle,
3115
+ .range-dot {
3116
+ display: none !important;
3117
+ }
3118
+
3119
+ /* Ocultar scroll siempre */
3120
+ .timeline-scroll {
3121
+ overflow-x: hidden !important;
3122
+ scrollbar-width: none !important;
3123
+ -ms-overflow-style: none !important;
3124
+ }
3125
+
3126
+ .timeline-scroll::-webkit-scrollbar {
3127
+ display: none !important;
3128
+ }
3129
+
3130
+ .scroll-arrow {
3131
+ display: none !important;
3132
+ }
3133
+ </style>