diff --git a/Elecciones-Web/frontend/src/features/legislativas/DevAppLegislativas.tsx b/Elecciones-Web/frontend/src/features/legislativas/DevAppLegislativas.tsx index 1c07354..2bbe9dd 100644 --- a/Elecciones-Web/frontend/src/features/legislativas/DevAppLegislativas.tsx +++ b/Elecciones-Web/frontend/src/features/legislativas/DevAppLegislativas.tsx @@ -27,7 +27,7 @@ export const DevAppLegislativas = () => { const sectionStyle = { border: '2px solid #007bff', borderRadius: '8px', - padding: '1rem 2rem', + padding: '2px', marginTop: '3rem', marginBottom: '3rem', backgroundColor: '#f8f9fa' diff --git a/Elecciones-Web/frontend/src/features/legislativas/nacionales/CongresoNacionalWidget.module.css b/Elecciones-Web/frontend/src/features/legislativas/nacionales/CongresoNacionalWidget.module.css new file mode 100644 index 0000000..07c6f50 --- /dev/null +++ b/Elecciones-Web/frontend/src/features/legislativas/nacionales/CongresoNacionalWidget.module.css @@ -0,0 +1,282 @@ +/* src/features/legislativas/nacionales/CongresoNacionalWidget.module.css */ + +/* --- SOLUCIÓN PARA FUENTES Y ESTILOS GLOBALES --- */ +.congresoContainer, +.congresoContainer * { + font-family: "Public Sans", system-ui, sans-serif !important; + box-sizing: border-box; +} + +.congresoContainer { + display: flex; + gap: 1.5rem; + background-color: #ffffff; + border: 1px solid #e0e0e0; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05); + padding: 1rem; + border-radius: 8px; + max-width: 900px; + margin: 20px auto; + color: #333333; + --primary-accent-color: #007bff; /* Movida aquí desde :root */ +} + +.congresoGrafico { + flex: 2; + min-width: 300px; + display: flex; + flex-direction: column; +} + +.congresoHemicicloWrapper { + flex-grow: 1; + display: flex; + align-items: center; + justify-content: center; + width: 100%; +} + +.congresoHemicicloWrapper.isHovering :global(.party-block:not(:hover)) { + opacity: 0.3; +} + +.congresoGrafico svg { + width: 100%; + height: auto; + animation: fadeIn 0.8s ease-in-out; +} + +@keyframes fadeIn { + from { opacity: 0; transform: scale(0.9); } + to { opacity: 1; transform: scale(1); } +} + +.congresoFooter { + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.75rem 0.5rem 0 0.5rem; + margin-top: auto; + font-size: 0.8em; + color: #666; + border-top: 1px solid #eee; +} + +.footerLegend { + display: flex; + gap: 1.25rem; + align-items: center; +} + +.footerLegendItem { + display: flex; + align-items: center; + gap: 0.6rem; + font-size: 1.1em; +} + +.legendIcon { + display: inline-block; + width: 14px; + height: 14px; + border-radius: 50%; + box-sizing: border-box; +} + +.legendIconSolid { + background-color: #888; + border: 1px solid #777; +} + +.legendIconRing { + background-color: rgba(136, 136, 136, 0.3); + border: 1px solid #888; +} + +.footerTimestamp { + font-weight: 500; + font-size: 0.75em; +} + +.congresoSummary { + flex: 1; + border-left: 1px solid #e0e0e0; + padding-left: 1.25rem; + display: flex; + flex-direction: column; + justify-content: flex-start; +} + +.congresoSummary h3 { + margin-top: 0; + margin-bottom: 0.75rem; + font-size: 1.4em; + color: #212529; +} + +.chamberTabs { + display: flex; + margin-bottom: 1rem; + border: 1px solid #dee2e6; + border-radius: 6px; + overflow: hidden; +} + +.chamberTabs button { + flex: 1; + padding: 0.5rem 0.5rem; + border: none; + background-color: #f8f9fa; + color: #6c757d; + font-family: inherit; + font-size: 1em; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease-in-out; +} + +.chamberTabs button:first-child { + border-right: 1px solid #dee2e6; +} + +.chamberTabs button:hover { + background-color: #e9ecef; +} + +.chamberTabs button.active { + background-color: var(--primary-accent-color); + color: #ffffff; +} + +.summaryMetric { + display: flex; + justify-content: space-between; + align-items: baseline; + margin-bottom: 0.25rem; + font-size: 1.1em; +} + +.summaryMetric strong { + font-size: 1.5em; + font-weight: 700; + color: var(--primary-accent-color); +} + +.congresoSummary hr { + border: none; + border-top: 1px solid #e0e0e0; + margin: 1rem 0; +} + +.partidoListaContainer { + flex-grow: 1; + overflow-y: auto; + min-height: 0; + padding-right: 8px; +} + +.partidoLista { + list-style: none; + padding: 0; + margin: 0; +} + +.partidoLista li { + display: flex; + align-items: center; + margin-bottom: 0.85rem; +} + +.partidoColorBox { + width: 16px; + height: 16px; + border-radius: 4px; + margin-right: 12px; + flex-shrink: 0; +} + +.partidoNombre { + flex-grow: 1; +} + +.partidoBancas { + font-weight: 700; + font-size: 1.1em; +} + +@media (max-width: 768px) { + .congresoContainer { + flex-direction: column; + padding: 0.5rem; + height: auto; + max-height: none; + } + + .congresoSummary { + border-left: none; + padding-left: 0; + border-top: 1px solid #e0e0e0; + } + + .partidoListaContainer { + overflow-y: visible; + max-height: none; + } + + .congresoFooter { + flex-direction: column; + align-items: center; + gap: 0.5rem; + padding: 0.75rem 0rem; + } + + .footerLegend { + gap: 0.75rem; + } + + .footerLegendItem{ + font-size: 1em; + } + + .footerTimestamp { + font-size: 0.75em; + } +} + +@media (min-width: 769px) { + .congresoContainer { + flex-direction: row; + align-items: stretch; + height: 500px; + } +} + +/* --- ESTILOS PARA TOOLTIP --- */ +/* Usamos :global() para apuntar a clases e IDs generados por la librería react-tooltip */ +:global(.seat-tooltip) { + display: flex; + flex-direction: column; + align-items: center; + gap: 5px; + padding: 8px; + background-color: white; +} +:global(.seat-tooltip img) { + width: 60px; + height: 60px; + border-radius: 50%; + object-fit: cover; + border: 2px solid #ccc; +} +:global(.seat-tooltip p) { + margin: 0; + font-size: 12px; + font-weight: bold; + color: #333; +} + +:global(#seat-tooltip.react-tooltip) { + opacity: 1 !important; + background-color: white; +} \ No newline at end of file diff --git a/Elecciones-Web/frontend/src/features/legislativas/nacionales/CongresoNacionalWidget.tsx b/Elecciones-Web/frontend/src/features/legislativas/nacionales/CongresoNacionalWidget.tsx index 514af51..a8a5da3 100644 --- a/Elecciones-Web/frontend/src/features/legislativas/nacionales/CongresoNacionalWidget.tsx +++ b/Elecciones-Web/frontend/src/features/legislativas/nacionales/CongresoNacionalWidget.tsx @@ -5,7 +5,8 @@ import { Tooltip } from 'react-tooltip'; import { DiputadosNacionalesLayout } from '../../../components/common/DiputadosNacionalesLayout'; import { SenadoresNacionalesLayout } from '../../../components/common/SenadoresNacionalesLayout'; import { getComposicionNacional, type ComposicionNacionalData, type PartidoComposicionNacional } from '../../../apiService'; -import '../provinciales/CongresoWidget.css'; +// 1. La importación de CSS ahora se hace como un módulo +import styles from './CongresoNacionalWidget.module.css'; interface CongresoNacionalWidgetProps { eleccionId: number; @@ -71,11 +72,12 @@ const WidgetContent = ({ eleccionId }: CongresoNacionalWidgetProps) => { return adjustedPartyData; }, [partidosOrdenados, datosCamaraActual.presidenteBancada, camaraActiva]); + // 2. Todas las props 'className' ahora usan el objeto 'styles' return ( -
-
+
+
setIsHovering(true)} onMouseLeave={() => setIsHovering(false)} > @@ -92,53 +94,51 @@ const WidgetContent = ({ eleccionId }: CongresoNacionalWidgetProps) => { /> }
-
-
-
- {/* Usamos la nueva clase CSS para el círculo sólido */} - +
+
+
+ Bancas en juego
-
- {/* Reemplazamos el SVG por un span con la nueva clase para el anillo */} - +
+ Bancas previas
-
+
Última Actualización: {formatTimestamp(datosCamaraActual.ultimaActualizacion)}
-
-
- -

{datosCamaraActual.camaraNombre}

-
+
Total de Bancas {datosCamaraActual.totalBancas}
-
+
Bancas en Juego {datosCamaraActual.bancasEnJuego}

-
-
    +
    +
      {partidosOrdenados .filter(p => p.bancasTotales > 0) .map((partido: PartidoComposicionNacional) => (
    • - - {partido.nombreCorto || partido.nombre} + + {partido.nombreCorto || partido.nombre} {partido.bancasTotales} @@ -155,7 +155,7 @@ const WidgetContent = ({ eleccionId }: CongresoNacionalWidgetProps) => { export const CongresoNacionalWidget = ({ eleccionId }: CongresoNacionalWidgetProps) => { return ( - Cargando composición del congreso...
    }> + Cargando composición del congreso...
}> ); diff --git a/Elecciones-Web/frontend/src/features/legislativas/nacionales/HomeCarouselWidget.css b/Elecciones-Web/frontend/src/features/legislativas/nacionales/HomeCarouselWidget.css deleted file mode 100644 index 9e79dfa..0000000 --- a/Elecciones-Web/frontend/src/features/legislativas/nacionales/HomeCarouselWidget.css +++ /dev/null @@ -1,240 +0,0 @@ -/* src/features/legislativas/nacionales/HomeCarouselWidget.css */ - -.home-carousel-widget { - --primary-text: #212529; - --secondary-text: #6c757d; - --border-color: #dee2e6; - --background-light: #f8f9fa; - --background-white: #ffffff; - --shadow: 0 2px 8px rgba(0, 0, 0, 0.07); - --font-family-sans: "Roboto", system-ui, sans-serif; -} - -.home-carousel-widget { - font-family: var(--font-family-sans); - background-color: var(--background-white); - border: 1px solid var(--border-color); - border-radius: 8px; - padding: 0.75rem; - max-width: 1200px; - margin: 2rem auto; -} - -.widget-title { - font-size: 1.2rem; - font-weight: 900; - color: var(--primary-text); - margin: 0 0 0.5rem 0; - padding-bottom: 0.5rem; - border-bottom: 1px solid var(--border-color); - text-align: left; -} - -.top-stats-bar { - display: flex; - justify-content: space-around; - background-color: transparent; - border: 1px solid var(--border-color); - border-radius: 8px; - padding: 0.3rem 0.5rem; - margin-bottom: 0.5rem; -} - -.top-stats-bar > div { - display: flex; - align-items: baseline; - gap: 0.5rem; - border-right: 1px solid var(--border-color); - padding: 0 0.5rem; - flex-grow: 1; - justify-content: center; -} -.top-stats-bar > div:last-child { border-right: none; } -.top-stats-bar span { font-size: 0.9rem; color: var(--secondary-text); } -.top-stats-bar strong { font-size: 0.9rem; font-weight: 600; color: var(--primary-text); } - -.candidate-card { - display: flex; - align-items: center; - gap: 0.75rem; - background: var(--background-white); - border: 1px solid var(--border-color); - border-radius: 12px; - padding: 0.75rem; - box-shadow: var(--shadow); - height: 100%; - border-left: 5px solid; - border-left-color: var(--candidate-color, #ccc); - position: relative; -} - -.candidate-photo-wrapper { - flex-shrink: 0; - width: 60px; - height: 60px; - border-radius: 8px; - overflow: hidden; - background-color: var(--candidate-color, #e9ecef); -} - -.candidate-photo { - width: 100%; - height: 100%; - object-fit: cover; - box-sizing: border-box; -} - -.candidate-details { - flex-grow: 1; - display: flex; - justify-content: space-between; - align-items: center; - min-width: 0; -} - -.candidate-info { - display: flex; - flex-direction: column; - justify-content: center; - align-items:flex-start; - gap: 0.1rem; - min-width: 0; - margin-right: 0.75rem; -} - -.candidate-name, .party-name { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - display: block; - width: 100%; - text-transform: uppercase; -} -.candidate-name { - font-size: 0.95rem; - text-align: left; - font-weight: 700; - color: var(--primary-text); -} -.party-name { - font-size: 0.8rem; - text-align: left; - text-transform: uppercase; - color: var(--secondary-text); - text-transform: uppercase; -} - -.candidate-results { text-align: right; flex-shrink: 0; } -.percentage { - display: block; - font-size: 1.2rem; - font-weight: 700; - color: var(--primary-text); - line-height: 1.1; -} -.votes { - font-size: 0.75rem; - color: var(--secondary-text); - white-space: nowrap; -} - -.swiper-slide:not(:last-child) .candidate-card::after { - content: ''; - position: absolute; - right: -8px; - top: 20%; - bottom: 20%; - width: 1px; - background-color: var(--border-color); -} - -.swiper-button-prev, .swiper-button-next { - width: 30px; height: 30px; - background-color: rgba(255, 255, 255, 0.9); - border: 1px solid var(--border-color); - border-radius: 50%; - box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1); - transition: opacity 0.2s; - color: var(--secondary-text); -} -.swiper-button-prev:after, .swiper-button-next:after { - font-size: 18px; - font-weight: bold; -} -.swiper-button-prev { left: -10px; } -.swiper-button-next { right: -10px; } -.swiper-button-disabled { opacity: 0; pointer-events: none; } - -.widget-footer { - text-align: right; - font-size: 0.75rem; - color: var(--secondary-text); - margin-top: 0.5rem; -} - -.short-text { - display: none; /* Oculto por defecto en la vista de escritorio */ -} - -/* --- INICIO DE LA SECCIÓN DE ESTILOS PARA MÓVIL --- */ -@media (max-width: 768px) { - .home-carousel-widget { - padding: 0.75rem; - } - - /* 1. Centrar el título en móvil */ - .widget-title { - text-align: center; - font-size: 1.1rem; - } - - /* 2. Reestructurar la barra de estadísticas a 2x2 y usar textos cortos */ - .top-stats-bar { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 0.2rem; - padding: 0.3rem; - } - - .top-stats-bar > div { - padding: 0.25rem 0.5rem; - border-right: none; /* Quitar todos los bordes derechos */ - } - - .top-stats-bar > div:nth-child(odd) { - border-right: 1px solid var(--border-color); /* Restablecer borde solo para la columna izquierda */ - } - - /* Lógica de visibilidad de textos */ - .long-text { - display: none; /* Ocultar el texto largo en móvil */ - } - .short-text { - display:inline; /* Mostrar el texto corto en móvil */ - } - - /* Reducir fuentes para que quepan mejor */ - .top-stats-bar span { font-size: 0.8rem; text-align: left; } - .top-stats-bar strong { font-size: 0.85rem; text-align: right;} - - /* --- Botones del Carrusel (sin cambios) --- */ - .swiper-button-prev, .swiper-button-next { - width: 32px; - height: 32px; - top: 45%; - } - .swiper-button-prev { left: 2px; } - .swiper-button-next { right: 2px; } - - /* --- Ajustes en la tarjeta (sin cambios) --- */ - .candidate-card { gap: 0.5rem; padding: 0.5rem; } - .candidate-photo-wrapper { width: 50px; height: 50px; } - .candidate-name { font-size: 0.9rem; } - .percentage { font-size: 1.1rem; } - .votes { font-size: 0.7rem; } - - /* 3. Centrar el footer en móvil */ - .widget-footer { - text-align: center; - } -} \ No newline at end of file diff --git a/Elecciones-Web/frontend/src/features/legislativas/nacionales/HomeCarouselWidget.module.css b/Elecciones-Web/frontend/src/features/legislativas/nacionales/HomeCarouselWidget.module.css new file mode 100644 index 0000000..71615fd --- /dev/null +++ b/Elecciones-Web/frontend/src/features/legislativas/nacionales/HomeCarouselWidget.module.css @@ -0,0 +1,309 @@ +/* src/features/legislativas/nacionales/HomeCarouselWidget.module.css */ + +.homeCarouselWidget { + --primary-text: #212529; + --secondary-text: #6c757d; + --border-color: #dee2e6; + --background-light: #f8f9fa; + --background-white: #ffffff; + --shadow: 0 2px 8px rgba(0, 0, 0, 0.07); + --font-family-sans: "Roboto", system-ui, sans-serif; +} + +.homeCarouselWidget, +.homeCarouselWidget * { + font-family: var(--font-family-sans) !important; + box-sizing: border-box; +} + +.homeCarouselWidget { + background-color: var(--background-white); + border: 1px solid var(--border-color); + border-radius: 8px; + padding: 0.75rem; + max-width: 1200px; + margin: 2rem auto; + position: relative; +} + +.carouselContainer { + position: relative; +} + +.widgetTitle { + font-size: 1.2rem; + font-weight: 900; + color: var(--primary-text); + margin: 0 0 0.5rem 0; + padding-bottom: 0.5rem; + border-bottom: 1px solid var(--border-color); + text-align: left; +} + +.topStatsBar { + display: flex; + justify-content: space-around; + background-color: transparent; + border: 1px solid var(--border-color); + border-radius: 8px; + padding: 0.3rem 0.5rem; + margin-bottom: 0.5rem; +} + +.topStatsBar > div { + display: flex; + align-items: baseline; + gap: 0.5rem; + border-right: 1px solid var(--border-color); + padding: 0 0.5rem; + flex-grow: 1; + justify-content: center; +} +.topStatsBar > div:last-child { border-right: none; } +.topStatsBar span { font-size: 0.9rem; color: var(--secondary-text); } +.topStatsBar strong { font-size: 0.9rem; font-weight: 600; color: var(--primary-text); } + +.candidateCard { + display: flex; + align-items: center; + gap: 0.75rem; + background: var(--background-white); + border: 1px solid var(--border-color); + border-radius: 12px; + padding: 0.75rem; + box-shadow: var(--shadow); + border-left: 5px solid; + border-left-color: var(--candidate-color, #ccc); + position: relative; +} + +.candidatePhotoWrapper { + flex-shrink: 0; + width: 60px; + height: 60px; + border-radius: 8px; + overflow: hidden; + background-color: var(--candidate-color, #e9ecef); +} + +.candidatePhoto { + width: 100% !important; + height: 100% !important; + object-fit: cover; + box-sizing: border-box; +} + +.candidateDetails { + flex-grow: 1; + display: flex; + justify-content: space-between; + align-items: center; + min-width: 0; +} + +.candidateInfo { + display: flex; + flex-direction: column; + justify-content: center; + align-items:flex-start; + gap: 0.1rem; + min-width: 0; + margin-right: 0.75rem; +} + +.candidateName, .partyName { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: block; + width: 100%; + margin: 0; + color: var(--primary-text); + text-align: left; +} +.candidateName { + font-size: 0.95rem; + font-weight: 700; +} +.partyName { + font-size: 0.8rem; + text-transform: uppercase; + color: var(--secondary-text); + font-weight: 400; +} + +.candidateResults { text-align: right; flex-shrink: 0; } +.percentage { + display: block; + font-size: 1.2rem; + font-weight: 700; + color: var(--primary-text); + line-height: 1.1; +} +.votes { + font-size: 0.75rem; + color: var(--secondary-text); + white-space: nowrap; +} + +/* Estilo base para ambos botones */ +.navButton { + width: 30px; + height: 30px; + background-color: rgba(255, 255, 255, 0.9); + border: 1px solid var(--border-color); + border-radius: 50%; + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1); + transition: opacity 0.2s; + position: absolute; + top: 50%; + transform: translateY(-50%); + margin-top: 0; + z-index: 10; + cursor: pointer; +} + +/* Usamos el pseudo-elemento ::after para mostrar el icono SVG como fondo */ +.navButton::after { + content: ''; /* Es necesario para que el pseudo-elemento se muestre */ + display: block; + width: 100%; + height: 100%; + background-repeat: no-repeat; + background-position: center; + /* Ajustamos el tamaño del icono dentro del botón */ + background-size: 75%; +} + +/* Posición y contenido específico para cada botón */ +.navButtonPrev { + left: 10px; +} +.navButtonPrev::after { + /* SVG de flecha izquierda (chevron) codificado en Base64 */ + background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiMyMTI1MjkiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cG9seWxpbmUgcG9pbnRzPSIxNSA2IDkgMTIgMTUgMTgiPjwvcG9seWxpbmU+PC9zdmc+"); +} + +.navButtonNext { + right: 10px; +} +.navButtonNext::after { + /* SVG de flecha derecha (chevron) codificado en Base64 */ + background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiMyMTI1MjkiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cG9seWxpbmUgcG9pbnRzPSI5IDYgMTUgMTIgOSAxOCI+PC9wb2x5bGluZT48L3N2Zz4="); +} + +/* Swiper añade esta clase al botón cuando está deshabilitado */ +.navButton.swiper-button-disabled { + opacity: 0; + pointer-events: none; +} + +.homeCarouselWidget :global(.swiper-slide) { + background: transparent !important; + color: initial !important; + text-align: left !important; + height: auto !important; +} + +.homeCarouselWidget :global(.swiper-slide:not(:last-child)) .candidateCard::after { + content: ''; + position: absolute; + right: -8px; + top: 20%; + bottom: 20%; + width: 1px; + background-color: var(--border-color); +} + +/* --- INICIO DE LA MODIFICACIÓN DE FLECHAS --- */ + +.homeCarouselWidget :global(.swiper-button-prev), +.homeCarouselWidget :global(.swiper-button-next) { + width: 30px !important; + height: 30px !important; + background-color: rgba(255, 255, 255, 0.9) !important; + border: 1px solid var(--border-color); + border-radius: 50%; + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1); + transition: opacity 0.2s; + position: absolute !important; + top: 50% !important; + transform: translateY(-50%) !important; + margin-top: 0 !important; + z-index: 10; +} + +.homeCarouselWidget :global(.swiper-button-prev:after), +.homeCarouselWidget :global(.swiper-button-next:after) { + display: block !important; + font-family: 'swiper-icons'; + font-size: 14px !important; + font-weight: bold !important; + color: var(--primary-text) !important; +} + +.homeCarouselWidget :global(.swiper-button-prev) { left: 10px !important; } +.homeCarouselWidget :global(.swiper-button-next) { right: 10px !important; } + +.homeCarouselWidget :global(.swiper-button-disabled) { + opacity: 0 !important; + pointer-events: none !important; +} + +.widgetFooter { + text-align: right; + font-size: 0.75rem; + color: var(--secondary-text); + margin-top: 0.5rem; +} + +.shortText { + display: none; +} + +@media (max-width: 768px) { + .homeCarouselWidget .widgetTitle { text-align: center; font-size: 1.1rem; } + .homeCarouselWidget .topStatsBar { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.2rem; padding: 0.3rem; } + .homeCarouselWidget .topStatsBar > div { padding: 0.25rem 0.5rem; border-right: none; } + .homeCarouselWidget .topStatsBar > div:nth-child(odd) { border-right: 1px solid var(--border-color); } + .homeCarouselWidget .longText { display: none; } + .homeCarouselWidget .shortText { display:inline; } + .homeCarouselWidget .topStatsBar span { font-size: 0.8rem; text-align: left; } + .homeCarouselWidget .topStatsBar strong { font-size: 0.85rem; text-align: right; } + + /* Ajustamos los botones custom en mobile */ + .navButton { + width: 32px; + height: 32px; + } + .navButton::after { + line-height: 32px; + } + .navButtonPrev { left: 5px; } + .navButtonNext { right: 5px; } + + .homeCarouselWidget .candidateCard { gap: 0.5rem; padding: 0.5rem; } + .homeCarouselWidget .candidatePhotoWrapper { width: 50px; height: 50px; } + .homeCarouselWidget .candidateName { font-size: 0.9rem; } + .homeCarouselWidget .percentage { font-size: 1.1rem; } + .homeCarouselWidget .votes { font-size: 0.7rem; } + .homeCarouselWidget .widgetFooter { text-align: center; } +} + +/* Mantenemos estos estilos globales por si acaso */ +.homeCarouselWidget :global(.swiper-slide) { + background: transparent !important; + color: initial !important; + text-align: left !important; + height: auto !important; +} + +.homeCarouselWidget :global(.swiper-slide:not(:last-child)) .candidateCard::after { + content: ''; + position: absolute; + right: -8px; + top: 20%; + bottom: 20%; + width: 1px; + background-color: var(--border-color); +} \ No newline at end of file diff --git a/Elecciones-Web/frontend/src/features/legislativas/nacionales/HomeCarouselWidget.tsx b/Elecciones-Web/frontend/src/features/legislativas/nacionales/HomeCarouselWidget.tsx index 10ecee8..4d9967d 100644 --- a/Elecciones-Web/frontend/src/features/legislativas/nacionales/HomeCarouselWidget.tsx +++ b/Elecciones-Web/frontend/src/features/legislativas/nacionales/HomeCarouselWidget.tsx @@ -10,7 +10,7 @@ import { Navigation, A11y } from 'swiper/modules'; import 'swiper/css'; // @ts-ignore import 'swiper/css/navigation'; -import './HomeCarouselWidget.css'; +import styles from './HomeCarouselWidget.module.css'; interface Props { eleccionId: number; @@ -22,14 +22,12 @@ interface Props { const formatPercent = (num: number | null | undefined) => `${(num || 0).toFixed(2).replace('.', ',')}%`; const formatNumber = (num: number) => num.toLocaleString('es-AR'); -// --- Lógica de formateo de fecha --- const formatDateTime = (dateString: string | undefined | null) => { if (!dateString) return '...'; try { const date = new Date(dateString); - // Verificar si la fecha es válida if (isNaN(date.getTime())) { - return dateString; // Si no se puede parsear, devolver el string original + return dateString; } const day = String(date.getDate()).padStart(2, '0'); const month = String(date.getMonth() + 1).padStart(2, '0'); @@ -38,7 +36,7 @@ const formatDateTime = (dateString: string | undefined | null) => { const minutes = String(date.getMinutes()).padStart(2, '0'); return `${day}/${month}/${year}, ${hours}:${minutes} hs.`; } catch (e) { - return dateString; // En caso de cualquier error, devolver el string original + return dateString; } }; @@ -52,82 +50,94 @@ export const HomeCarouselWidget = ({ eleccionId, distritoId, categoriaId, titulo if (error || !data) return
No se pudieron cargar los datos.
; return ( -
-

{titulo}

+
+

{titulo}

-
+
Participación {formatPercent(data.estadoRecuento?.participacionPorcentaje)}
- Mesas escrutadas - Escrutado + Mesas escrutadas + Escrutado {formatPercent(data.estadoRecuento?.mesasTotalizadasPorcentaje)}
- Votos en blanco - En blanco + Votos en blanco + En blanco {formatPercent(data.votosEnBlancoPorcentaje)}
- Votos totales - Votos + Votos totales + Votos {formatNumber(data.votosTotales)}
- - {data.resultados.map(candidato => ( - -
+
+ + {data.resultados.map(candidato => ( + +
-
- -
+
+ +
-
-
- {candidato.nombreCandidato ? ( - // CASO 1: Hay un candidato (se muestran dos líneas) - <> - - {candidato.nombreCandidato} - - +
+
+ {candidato.nombreCandidato ? ( + <> + + {candidato.nombreCandidato} + + + {candidato.nombreCortoAgrupacion || candidato.nombreAgrupacion} + + + ) : ( + {candidato.nombreCortoAgrupacion || candidato.nombreAgrupacion} - - ) : ( - // CASO 2: No hay candidato (se muestra solo una línea) - - {candidato.nombreCortoAgrupacion || candidato.nombreAgrupacion} - - )} -
-
- {formatPercent(candidato.porcentaje)} - {formatNumber(candidato.votos)} votos + )} +
+
+ {formatPercent(candidato.porcentaje)} + {formatNumber(candidato.votos)} votos +
+
+ + ))} + -
- - ))} - +
+
+
-
+
Última actualización: {formatDateTime(data.ultimaActualizacion)}
diff --git a/Elecciones-Web/frontend/src/features/legislativas/nacionales/PanelNacional.css b/Elecciones-Web/frontend/src/features/legislativas/nacionales/PanelNacional.css deleted file mode 100644 index 52bfafe..0000000 --- a/Elecciones-Web/frontend/src/features/legislativas/nacionales/PanelNacional.css +++ /dev/null @@ -1,920 +0,0 @@ -/* src/features/legislativas/nacionales/PanelNacional.css */ -.panel-nacional-container { - font-family: 'Roboto', sans-serif; - max-width: 1200px; - margin: auto; - border: 1px solid #e0e0e0; - border-radius: 8px; - position: relative; - padding: 10px; -} - -.panel-header { - padding: 1rem 1.5rem; - border-bottom: 1px solid #e0e0e0; - position: relative; - z-index: 20; - background-color: white; -} - -/* Contenedor para alinear título y selector */ -.header-top-row { - display: flex; - justify-content: flex-start; - /* Alinea los items al inicio */ - align-items: center; - gap: 2rem; - /* Añade un espacio de separación de 2rem entre el selector y el breadcrumb */ -} - -.categoria-selector { - min-width: 220px; -} - -/* El contenedor principal del selector (la parte visible antes de hacer clic) */ -.categoria-selector__control { - border-radius: 8px !important; - border: 1px solid #e0e0e0 !important; - box-shadow: none !important; - transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out; -} - -/* Estilo cuando el selector está enfocado (seleccionado) */ -.categoria-selector__control--is-focused { - border-color: #007bff !important; - box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25) !important; -} - -/* El texto del valor seleccionado */ -.categoria-selector__single-value { - font-weight: 500; - color: #333; -} - -/* El menú desplegable que contiene las opciones */ -.categoria-selector__menu { - border-radius: 8px !important; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1) !important; - border: 1px solid #e0e0e0 !important; - margin-top: 4px !important; - /* Pequeño espacio entre el control y el menú */ -} - -/* Cada una de las opciones en la lista */ -.categoria-selector__option { - cursor: pointer; - transition: background-color 0.2s, color 0.2s; -} - -/* Estilo de una opción cuando pasas el mouse por encima (estado 'focused') */ -.categoria-selector__option--is-focused { - background-color: #f0f8ff; - /* Un azul muy claro */ - color: #333; -} - -/* Estilo de la opción que está actualmente seleccionada */ -.categoria-selector__option--is-selected { - background-color: #007bff; - color: white; -} - -/* La pequeña línea vertical que separa el contenido del indicador (la flecha) */ -.categoria-selector__indicator-separator { - display: none; - /* La ocultamos para un look más limpio */ -} - -/* El indicador (la flecha hacia abajo) */ -.categoria-selector__indicator { - color: #a0a0a0; - transition: color 0.2s; -} - -.categoria-selector__indicator:hover { - color: #333; -} - -/* --- ESTILOS MODERNOS PARA BREADCRUMBS --- */ - -.breadcrumbs-container { - display: flex; - align-items: center; - gap: 0.5rem; - /* Espacio entre elementos */ - font-size: 1rem; -} - -.breadcrumb-item, -.breadcrumb-item-actual { - display: flex; - align-items: center; - padding: 0.4rem 0.8rem; - border-radius: 8px; - /* Bordes redondeados para efecto píldora */ - transition: background-color 0.2s ease-in-out; -} - -.breadcrumb-item { - background-color: #f0f0f0; - border: 1px solid #e0e0e0; - color: #333; - cursor: pointer; - font-weight: 500; -} - -.breadcrumb-item:hover { - background-color: #e0e0e0; - border-color: #d1d1d1; -} - -.breadcrumb-item-actual { - background-color: transparent; - color: #000; - font-weight: 700; - /* Más peso para el nivel actual */ -} - -.breadcrumb-icon { - margin-right: 0.4rem; - font-size: 1rem; -} - -.breadcrumb-separator { - color: #a0a0a0; - /* Color sutil para el separador */ - font-size: 1.2rem; -} - -.panel-main-content { - display: flex; - height: 75vh; - min-height: 500px; - transition: all 0.5s ease-in-out; -} - -.mapa-column { - flex: 2; - position: relative; - transition: flex 0.5s ease-in-out; -} - -.resultados-column { - flex: 1; - overflow-y: auto; - padding: 1.25rem; - transition: all 0.5s ease-in-out; - min-width: 320px; -} - -/* --- AJUSTES EN FILAS DE PARTIDOS --- */ -.partido-fila { - display: flex; - align-items: center; - gap: 0.75rem; - /* ANTES: 1rem */ - padding: 0.75rem 0; - /* ANTES: 1rem 0 */ - border-bottom: 1px solid #f0f0f0; - border-left: 5px solid; - border-radius: 12px; - padding-left: 1rem; -} - -.partido-logo { - flex-shrink: 0; - width: 65px; - height: 65px; - border-radius: 12px; - box-sizing: border-box; -} - -.partido-logo img { - width: 100%; - height: 100%; - border-radius: 12px; -} - -.partido-main-content { - flex-grow: 1; - display: grid; - grid-template-columns: 1fr auto; - grid-template-rows: auto auto; - align-items: center; - gap: 0.25rem 0.75rem; - /* ANTES: gap: 0.25rem 1rem */ -} - -.partido-top-row { - display: contents; -} - -.partido-info-wrapper { - min-width: 0; - text-align: left; -} - -.partido-nombre { - font-weight: 700; - font-size: 1rem; - color: #212529; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - line-height: 1.2; - text-transform: uppercase; -} - -.partido-nombre-normal { - font-size: 1rem; - color: #212529; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - line-height: 1.2; - text-transform: uppercase; -} - -.candidato-nombre { - font-size: 0.75rem; - /* ANTES: 0.8rem */ - color: #6c757d; - text-transform: uppercase; - font-weight: 500; - line-height: 1.1; -} - -.partido-stats { - flex-shrink: 0; - text-align: right; - padding-left: 1rem; -} - -.partido-porcentaje { - font-size: 1.35rem; - /* ANTES: 1.5rem */ - font-weight: 700; - display: block; -} - -.partido-votos { - font-size: 0.9rem; - /* ANTES: 1rem */ - color: #666; - display: block; -} - -.partido-barra-background { - height: 12px; - /* ANTES: 20px */ - background-color: #f0f0f0; - border-radius: 4px; - grid-column: 1 / 3; -} - -.partido-barra-foreground { - height: 100%; - border-radius: 4px; - transition: width 0.5s ease-in-out; -} - -/* --- AJUSTES EN CÍRCULOS DE ESTADÍSTICAS --- */ -.panel-estado-recuento { - display: flex; - justify-content: space-around; - padding-bottom: 1rem; - /* ANTES: 1.5rem */ - margin-bottom: 1rem; - /* ANTES: 1.5rem */ - border-bottom: 1px solid #e0e0e0; -} - -.estado-item { - width: 95px; - /* ANTES: 100px */ - text-align: center; -} - -.estado-item span { - margin-top: 0.5rem; - font-size: 0.85rem; - /* ANTES: 0.9rem */ - color: #666; - display: block; -} - -/* --- MAPA Y ELEMENTOS ASOCIADOS --- */ -.mapa-componente-container { - width: 100%; - height: 100%; - position: relative; - overflow: hidden; -} - -.mapa-render-area { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; -} - -.mapa-volver-btn { - position: absolute; - top: 10px; - left: 10px; - z-index: 10; - padding: 8px 12px; - background-color: white; - border: 1px solid #ccc; - border-radius: 4px; - cursor: pointer; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); -} - -.rsm-zoomable-group { - transition: transform 0.75s ease-in-out; -} - -/* Desactivar la transición durante el arrastre */ -.rsm-zoomable-group.panning { - transition: none; -} - -.panel-main-content.panel-collapsed .mapa-column { - flex: 1 1 100%; -} - -.panel-main-content.panel-collapsed .resultados-column { - flex-basis: 0; - min-width: 0; - max-width: 0; - padding: 0; - overflow: hidden; -} - -.panel-toggle-btn { - position: absolute; - top: 50%; - right: 10px; - transform: translateY(-50%); - z-index: 10; - width: 30px; - height: 50px; - border: 1px solid #ccc; - background-color: white; - border-radius: 4px 0 0 4px; - cursor: pointer; - font-size: 1.3rem; - font-weight: bold; - color: #555; - display: flex; - align-items: center; - justify-content: center; - box-shadow: -2px 0 5px rgba(0, 0, 0, 0.1); - transition: background-color 0.2s; -} - -.panel-toggle-btn:hover { - background-color: #f0f0f0; -} - -.rsm-geography { - stroke: #000000; - stroke-width: 0.25px; - outline: none; - transition: filter 0.2s ease-in-out; -} - -.rsm-geography:not(.selected):hover { - filter: brightness(1.25); - /* Mantenemos el brillo */ - stroke: #ffffff; - /* Color del borde a blanco */ - stroke-width: 0.25px; - paint-order: stroke; - /* Asegura que el borde se dibuje encima del relleno */ -} - -.rsm-geography.selected { - stroke: #000000; - stroke-width: 0.25px; - filter: none; - pointer-events: none; -} - -.rsm-geography-faded, -.rsm-geography-faded-municipality { - opacity: 0.5; - pointer-events: none; -} - -.caba-comuna-geography { - stroke: #000000; - stroke-width: 0.05px; -} - -.caba-comuna-geography:not(.selected):hover { - stroke: #000000; - stroke-width: 0.055px; - filter: brightness(1.25); -} - -.transition-spinner { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: rgba(255, 255, 255, 0.5); - z-index: 20; - display: flex; - align-items: center; - justify-content: center; -} - -.transition-spinner::after { - content: ''; - width: 50px; - height: 50px; - border: 5px solid rgba(0, 0, 0, 0.2); - border-top-color: #007bff; - border-radius: 50%; - animation: spin 1s linear infinite; -} - -@keyframes spin { - to { - transform: rotate(360deg); - } -} - -.caba-magnifier-container { - position: absolute; - height: auto; - transform: translate(-50%, -50%); - pointer-events: none; -} - -.caba-lupa-svg { - width: 100%; - height: auto; - pointer-events: none; -} - -.caba-lupa-interactive-area { - pointer-events: all; - cursor: pointer; - filter: drop-shadow(0px 2px 4px rgba(0, 0, 0, 0.25)); - transition: transform 0.2s ease-in-out; -} - -.caba-lupa-interactive-area:hover { - filter: brightness(1.15); - stroke: #ffffff; - stroke-width: 0.25px; -} - -.skeleton-fila div { - background: #f6f7f8; - background-image: linear-gradient(to right, #f6f7f8 0%, #edeef1 20%, #f6f7f8 40%, #f6f7f8 100%); - background-repeat: no-repeat; - background-size: 800px 104px; - animation: shimmer 1s linear infinite; - border-radius: 4px; -} - -.skeleton-logo { - width: 65px; - height: 65px; -} - -.skeleton-text { - height: 1em; -} - -.skeleton-bar { - height: 20px; - margin-top: 4px; -} - -/* --- ESTILOS PARA LOS BOTONES DE ZOOM DEL MAPA --- */ -.zoom-controls-container { - position: absolute; - top: 5px; - right: 10px; - z-index: 30; - display: flex; - flex-direction: column; - gap: 5px; -} - -.zoom-btn { - width: 40px; - height: 40px; - background-color: white; - border: 1px solid #ccc; - border-radius: 8px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - font-size: 1.2rem; - transition: background-color 0.2s; -} - -.zoom-icon-wrapper { - display: flex; - align-items: center; - justify-content: center; -} - -.zoom-icon-wrapper svg { - width: 20px; - height: 20px; - color: #333; -} - -.zoom-btn.disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.zoom-btn:hover { - background-color: #f0f0f0; -} - -/* --- ESTILOS DE CURSOR PARA EL ARRASTRE DEL MAPA --- */ -.map-locked .rsm-geography { - cursor: pointer; -} - -.map-pannable .rsm-geography { - cursor: grab; -} - -.header-bottom-row { - display: flex; - justify-content: space-between; - align-items: center; - margin-top: 1rem; - gap: 1rem; -} - -.municipio-search-container { - min-width: 280px; - /* Ancho mínimo para el buscador en desktop */ -} - -/* --- MEDIA QUERY PARA RESPONSIVE (REFACTORIZADA) --- */ -@media (max-width: 800px) { - - .panel-nacional-container { - display: flex; - flex-direction: column; - height: 100vh; - padding: 0; - border: none; - border-radius: 0; - } - - .panel-header { - flex-shrink: 0; - padding: 1rem; - border-radius: 0; - } - - .panel-main-content { - flex-grow: 1; - position: relative; - height: auto; - min-height: 0; - } - - .panel-toggle-btn { - display: none; - } - - .header-top-row { - flex-direction: column; - align-items: flex-start; - gap: 1rem; - } - - .categoria-selector { - width: 100%; - } - - .mapa-column, - .resultados-column { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - box-sizing: border-box; - transition: opacity 0.2s ease-in-out, visibility 0.2s ease-in-out; - } - - .mapa-column { - z-index: 10; - } - - .resultados-column { - padding: 1rem; - overflow-y: auto; - z-index: 15; - } - - .panel-main-content.mobile-view-mapa .resultados-column { - opacity: 0; - visibility: hidden; - pointer-events: none; - } - - .panel-main-content.mobile-view-resultados .mapa-column { - opacity: 0; - visibility: hidden; - pointer-events: none; - } - - .resultados-column { - padding: 0.5rem; - overflow-y: auto; - z-index: 15; - padding-bottom: 50px; -} - -.mapa-column .mapa-componente-container, -.mapa-column .mapa-render-area { - height: 100%; -} - -.panel-partidos-container { - padding-bottom: 0; -} - -.zoom-controls-container, .mapa-volver-btn { - top: 15px; -} - - .header-bottom-row { - flex-direction: column; - align-items: stretch; - gap: 1rem; - } - - .municipio-search-container { - min-width: 100%; - /* El buscador ocupa todo el ancho en móvil */ - } - - @media (max-width: 900px) and (orientation: landscape) { - .panel-main-content { - display: flex; - flex-direction: row; - position: static; - height: 85vh; - min-height: 400px; - } - - .mapa-column, - .resultados-column { - position: static; - height: auto; - width: auto; - opacity: 1; - visibility: visible; - pointer-events: auto; - flex: 3; - overflow-y: auto; - } - - .resultados-column { - flex: 2; - min-width: 300px; - } - - .mobile-results-card-container { - display: none; - } - - .panel-toggle-btn { - display: flex; - - } - } -} - -/* --- ESTILOS PARA LA TARJETA DE RESULTADOS EN MÓVIL (ACTUALIZADOS) --- */ -.mobile-results-card-container { - position: absolute; - bottom: 0px; - left: 50%; - transform: translateX(-50%); - z-index: 40; - width: 95%; - max-width: 450px; - background-color: rgba(255, 255, 255, 0.95); - border-radius: 12px; - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15); - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); - border: 1px solid rgba(0, 0, 0, 0.1); - transition: all 0.3s ease-in-out; - display: flex; - flex-direction: column; -} - -.mobile-results-card-container.view-resultados .collapsible-section { - display: none; -} - -.mobile-results-card-container.view-resultados .mobile-card-view-toggle { - border-top: none; -} - - -.collapsible-section { - display: flex; - flex-direction: column; -} - -.mobile-results-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: 12px 18px; - cursor: pointer; -} - -.mobile-results-header .header-info { - display: flex; - align-items: baseline; - gap: 12px; -} - -.mobile-results-header .header-info h4 { - margin: 0; - font-size: 1.2rem; - font-weight: 700; -} - -/* SELECTOR ESPECÍFICO PARA EL TEXTO DE ACCIÓN */ -.mobile-results-header .header-info .header-action-text { - font-size: 0.8rem; - color: #6c757d; - font-weight: 500; - text-transform: uppercase; -} - -.mobile-results-header .header-toggle-icon { - font-size: 1.5rem; - color: #007bff; - transition: transform 0.3s; -} - -.mobile-results-content { - max-height: 0; - opacity: 0; - overflow: hidden; - transition: max-height 0.3s ease-in-out, opacity 0.3s ease-in-out, padding 0.3s ease-in-out; - padding: 0 15px; - border-top: 1px solid transparent; -} - -.mobile-results-card-container.expanded .mobile-results-content { - max-height: 500px; - opacity: 1; - padding: 5px 15px 15px 15px; - border-top-color: #e0e0e0; -} - -.mobile-result-row { - display: flex; - align-items: center; - gap: 10px; - padding: 8px 0; - border-bottom: 1px solid #f0f0f0; - border-left: 4px solid; - padding-left: 8px; -} - -.mobile-result-row:last-child { - border-bottom: none; -} - -.mobile-result-logo { - flex-shrink: 0; - width: 40px; - height: 40px; - border-radius: 8px; - box-sizing: border-box; -} - -.mobile-result-logo img { - width: 100%; - height: 100%; - border-radius: 8px; -} - -.mobile-result-info { - flex-grow: 1; - min-width: 0; -} - -.mobile-result-party-name { - display: block; - font-weight: 600; - font-size: 0.9rem; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.mobile-result-candidate-name { - display: block; - font-size: 0.75rem; - color: #6c757d; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.mobile-result-stats { - display: flex; - flex-direction: column; - align-items: flex-end; - flex-shrink: 0; -} - -.mobile-result-stats strong { - font-size: 0.95rem; - font-weight: 700; -} - -.mobile-result-stats span { - font-size: 0.7rem; - color: #6c757d; -} - -.no-results-text { - padding: 1rem; - text-align: center; - color: #6c757d; - font-size: 0.9rem; -} - -.mobile-card-view-toggle { - display: flex; - padding: 5px; - background-color: rgba(230, 230, 230, 0.6); - border-top: 1px solid rgba(0, 0, 0, 0.08); -} - -.mobile-card-view-toggle .toggle-btn { - flex: 1; - display: flex; - align-items: center; - justify-content: center; - gap: 8px; - padding: 10px 15px; - /* Aumentado para pantallas más grandes */ - border: none; - background-color: transparent; - border-radius: 25px; - cursor: pointer; - font-size: 1rem; - /* Mantenido para pantallas más grandes */ - font-weight: 500; - color: #555; - transition: all 0.2s ease-in-out; -} - -.mobile-card-view-toggle .toggle-btn.active { - background-color: #007bff; - color: white; - box-shadow: 0 2px 5px rgba(0, 123, 255, 0.2); -} - -/* Ajustes para pantallas pequeñas como el iPhone SE */ -@media (max-width: 380px) { - .mobile-results-header { - padding: 4px 10px; - } - - .mobile-results-header .header-info h4 { - font-size: 0.75rem; - text-transform: uppercase; - } - - .mobile-results-header .header-info .header-action-text { - font-size: 0.7rem; - } - - .mobile-card-view-toggle .toggle-btn { - padding: 6px 10px; - font-size: 0.8rem; - } -} \ No newline at end of file diff --git a/Elecciones-Web/frontend/src/features/legislativas/nacionales/PanelNacional.module.css b/Elecciones-Web/frontend/src/features/legislativas/nacionales/PanelNacional.module.css new file mode 100644 index 0000000..41ae60b --- /dev/null +++ b/Elecciones-Web/frontend/src/features/legislativas/nacionales/PanelNacional.module.css @@ -0,0 +1,539 @@ +/* src/features/legislativas/nacionales/PanelNacional.module.css */ + +/* --- SOLUCIÓN PARA FUENTES Y ESTILOS GLOBALES --- */ +.panelNacionalContainer, +.panelNacionalContainer * { + font-family: 'Roboto', sans-serif !important; + box-sizing: border-box; +} + +.panelNacionalContainer { + max-width: 1200px; + margin: auto; + border: 1px solid #e0e0e0; + border-radius: 8px; + position: relative; + padding: 10px; +} + +.panelHeader { + padding: 1rem 1.5rem; + border-bottom: 1px solid #e0e0e0; + position: relative; + z-index: 20; + background-color: white; +} + +.headerTopRow { + display: flex; + justify-content: flex-start; + align-items: center; + gap: 2rem; +} + +/* --- ESTILOS PARA REACT-SELECT USANDO MÓDULOS --- */ +.categoriaSelectorContainer { + min-width: 220px; +} + +.categoriaSelectorContainer :global(.categoriaSelector__control) { + border-radius: 8px !important; + border: 1px solid #e0e0e0 !important; + box-shadow: none !important; + transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out; +} + +.categoriaSelectorContainer :global(.categoriaSelector__control--is-focused) { + border-color: #007bff !important; + box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25) !important; +} + +.categoriaSelectorContainer :global(.categoriaSelector__single-value) { + font-weight: 500; + color: #333; +} + +.categoriaSelectorContainer :global(.categoriaSelector__menu) { + border-radius: 8px !important; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1) !important; + border: 1px solid #e0e0e0 !important; + margin-top: 4px !important; +} + +.categoriaSelectorContainer :global(.categoriaSelector__option) { + cursor: pointer; + transition: background-color 0.2s, color 0.2s; +} + +.categoriaSelectorContainer :global(.categoriaSelector__option--is-focused) { + background-color: #f0f8ff; + color: #333; +} + +.categoriaSelectorContainer :global(.categoriaSelector__option--is-selected) { + background-color: #007bff; + color: white; +} + +.categoriaSelectorContainer :global(.categoriaSelector__indicator-separator) { + display: none; +} + +.categoriaSelectorContainer :global(.categoriaSelector__indicator) { + color: #a0a0a0; + transition: color 0.2s; +} + +.categoriaSelectorContainer :global(.categoriaSelector__indicator:hover) { + color: #333; +} + + +/* --- ESTILOS MODERNOS PARA BREADCRUMBS --- */ +.breadcrumbsContainer { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 1rem; +} + +.breadcrumbItem, +.breadcrumbItemActual { + display: flex; + align-items: center; + padding: 0.4rem 0.8rem; + border-radius: 8px; + transition: background-color 0.2s ease-in-out; +} + +.breadcrumbItem { + background-color: #f0f0f0; + border: 1px solid #e0e0e0; + color: #333; + cursor: pointer; + font-weight: 500; +} + +.breadcrumbItem:hover { + background-color: #e0e0e0; + border-color: #d1d1d1; +} + +.breadcrumbItemActual { + background-color: transparent; + color: #000; + font-weight: 700; +} + +.breadcrumbIcon { + margin-right: 0.4rem; + font-size: 1rem; +} + +.breadcrumbSeparator { + color: #a0a0a0; + font-size: 1.2rem; +} + +.panelMainContent { + display: flex; + height: 75vh; + min-height: 500px; + transition: all 0.5s ease-in-out; +} + +.mapaColumn { + flex: 2; + position: relative; + transition: flex 0.5s ease-in-out; +} + +.resultadosColumn { + flex: 1; + overflow-y: auto; + padding: 1.25rem; + transition: all 0.5s ease-in-out; + min-width: 320px; +} + +.partidoFila { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.75rem 0; + border-bottom: 1px solid #f0f0f0; + border-left: 5px solid; + border-radius: 12px; + padding-left: 1rem; +} + +.partidoLogo { + flex-shrink: 0; + width: 65px; + height: 65px; + border-radius: 12px; +} + +.partidoLogo img { + width: 100%; + height: 100%; + border-radius: 12px; +} + +.partidoMainContent { + flex-grow: 1; + display: grid; + grid-template-columns: 1fr auto; + grid-template-rows: auto auto; + align-items: center; + gap: 0.25rem 0.75rem; +} + +.partidoTopRow { display: contents; } +.partidoInfoWrapper { min-width: 0; text-align: left; } + +.partidoNombre { + font-weight: 700; + font-size: 1rem; + color: #212529; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + line-height: 1.2; + text-transform: uppercase; +} + +.partidoNombreNormal { + font-size: 1rem; + color: #212529; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + line-height: 1.2; + text-transform: uppercase; +} + +.candidatoNombre { + font-size: 0.75rem; + color: #6c757d; + text-transform: uppercase; + font-weight: 500; + line-height: 1.1; +} + +.partidoStats { flex-shrink: 0; text-align: right; padding-left: 1rem; } +.partidoPorcentaje { font-size: 1.35rem; font-weight: 700; display: block; } +.partidoVotos { font-size: 0.9rem; color: #666; display: block; } + +.partidoBarraBackground { + height: 12px; + background-color: #f0f0f0; + border-radius: 4px; + grid-column: 1 / 3; +} + +.partidoBarraForeground { + height: 100%; + border-radius: 4px; + transition: width 0.5s ease-in-out; +} + +.panelEstadoRecuento { + display: flex; + justify-content: space-around; + padding-bottom: 1rem; + margin-bottom: 1rem; + border-bottom: 1px solid #e0e0e0; +} + +.estadoItem { + width: 95px; + text-align: center; +} + +.estadoItem span { + margin-top: 0.5rem; + font-size: 0.85rem; + color: #666; + display: block; +} + +/* --- ESTILOS PARA MAPA --- */ +/* --- INICIO DE LA CORRECCIÓN --- */ +.mapaComponenteContainer { + width: 100%; + height: 100%; + position: relative; /* Esta línea es la que faltaba */ + overflow: hidden; +} +/* --- FIN DE LA CORRECCIÓN --- */ + +.mapaRenderArea { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } + +.mapaVolverBtn, +.zoomBtn { + background-color: #ffffff; + border: 1px solid #e0e0e0; /* Borde más sutil */ + border-radius: 8px; /* Bordes más suaves */ + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08); /* Sombra más pronunciada y moderna */ + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease-in-out; /* Transición suave para todos los efectos */ + color: #333; +} + +.mapaVolverBtn:hover, +.zoomBtn:hover:not(:disabled) { + border-color: #007bff; /* Borde de acento */ + color: #007bff; /* Icono/texto de acento */ + transform: translateY(-2px); /* Efecto de "levantar" */ + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.12); +} + +.mapaVolverBtn:active, +.zoomBtn:active:not(:disabled) { + transform: translateY(0px); /* Botón "presionado" */ + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); /* Sombra interior */ + background-color: #f8f9fa; +} + +.mapaVolverBtn { + position: absolute; + top: 10px; + left: 10px; + z-index: 10; + padding: 8px 12px; + font-weight: 500; +} + +:global(.rsm-zoomable-group) { transition: transform 0.75s ease-in-out; } +:global(.rsm-zoomable-group.panning) { transition: none; } + +.panelMainContent.panelCollapsed .mapaColumn { flex: 1 1 100%; } + +.panelMainContent.panelCollapsed .resultadosColumn { + flex-basis: 0; + min-width: 0; + max-width: 0; + padding: 0; + overflow: hidden; +} + +.panelToggleBtn { + position: absolute; + top: 50%; + right: 10px; + transform: translateY(-50%); + z-index: 10; + width: 30px; + height: 50px; + border: 1px solid #ccc; + background-color: white; + border-radius: 4px 0 0 4px; + cursor: pointer; + font-size: 1.3rem; + font-weight: bold; + color: #555; + display: flex; + align-items: center; + justify-content: center; + box-shadow: -2px 0 5px rgba(0, 0, 0, 0.1); + transition: background-color 0.2s; +} + +.panelToggleBtn:hover { background-color: #f0f0f0; } + +:global(.rsm-geography) { + stroke: #000000; + stroke-width: 0.25px; + outline: none; + transition: filter 0.2s ease-in-out; +} +:global(.rsm-geography:not(.selected):hover) { + filter: brightness(1.25); + stroke: #ffffff; + stroke-width: 0.25px; + paint-order: stroke; +} +:global(.rsm-geography.selected) { + stroke: #000000; + stroke-width: 0.25px; + filter: none; + pointer-events: none; +} +:global(.rsm-geography-faded), :global(.rsm-geography-faded-municipality) { + opacity: 0.5; + pointer-events: none; +} +:global(.caba-comuna-geography) { + stroke: #000000; + stroke-width: 0.05px; +} +:global(.caba-comuna-geography:not(.selected):hover) { + stroke: #000000; + stroke-width: 0.055px; + filter: brightness(1.25); +} + +.transitionSpinner { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(255, 255, 255, 0.5); + z-index: 20; + display: flex; + align-items: center; + justify-content: center; +} +.transitionSpinner::after { + content: ''; + width: 50px; + height: 50px; + border: 5px solid rgba(0, 0, 0, 0.2); + border-top-color: #007bff; + border-radius: 50%; + animation: spin 1s linear infinite; +} +@keyframes spin { to { transform: rotate(360deg); } } + +.cabaMagnifierContainer { position: absolute; height: auto; transform: translate(-50%, -50%); pointer-events: none; } +.cabaLupaSvg { width: 100%; height: auto; pointer-events: none; } +.cabaLupaInteractiveArea { pointer-events: all; cursor: pointer; filter: drop-shadow(0px 2px 4px rgba(0, 0, 0, 0.25)); transition: transform 0.2s ease-in-out; } +.cabaLupaInteractiveArea:hover { filter: brightness(1.15); stroke: #ffffff; stroke-width: 0.25px; } + +.skeletonFila div { + background: #f6f7f8; + background-image: linear-gradient(to right, #f6f7f8 0%, #edeef1 20%, #f6f7f8 40%, #f6f7f8 100%); + background-repeat: no-repeat; + background-size: 800px 104px; + animation: shimmer 1s linear infinite; + border-radius: 4px; +} +.skeletonLogo { width: 65px; height: 65px; } +.skeletonText { height: 1em; } +.skeletonBar { height: 20px; margin-top: 4px; } + +.zoomControlsContainer { + position: absolute; + top: 10px; + right: 10px; + z-index: 30; + display: flex; + flex-direction: column; + gap: 8px; /* Un poco más de espacio */ +} + +/* Estilos específicos para los botones de zoom */ +.zoomBtn { + width: 40px; + height: 40px; +} + +.zoomIconWrapper svg { + width: 22px; /* Iconos ligeramente más grandes */ + height: 22px; +} + +/* Estilo para el botón deshabilitado */ +.zoomBtn:disabled, +.zoomBtn.disabled { /* Cubrimos ambos casos */ + opacity: 0.6; + cursor: not-allowed; + background-color: #f8f9fa; +} + +:global(.map-locked .rsm-geography) { cursor: pointer; } +:global(.map-pannable .rsm-geography) { cursor: grab; } + +.headerBottomRow { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 1rem; + gap: 1rem; +} +.municipioSearchContainer { min-width: 280px; } + +@media (max-width: 800px) { + .panelNacionalContainer { display: flex; flex-direction: column; height: 100vh; padding: 0; border: none; border-radius: 0; } + .panelHeader { flex-shrink: 0; padding: 1rem; border-radius: 0; } + .panelMainContent { flex-grow: 1; position: relative; height: auto; min-height: 0; } + .panelToggleBtn { display: none; } + .headerTopRow { flex-direction: column; align-items: flex-start; gap: 1rem; } + .categoriaSelectorContainer { width: 100%; } + .mapaColumn, + .resultadosColumn { position: absolute; top: 0; left: 0; width: 100%; height: 100%; transition: opacity 0.2s ease-in-out, visibility 0.2s ease-in-out; } + .mapaColumn { z-index: 10; } + .resultadosColumn { padding: 1rem; overflow-y: auto; z-index: 15; } + .panelMainContent.mobile-view-mapa .resultadosColumn { opacity: 0; visibility: hidden; pointer-events: none; } + .panelMainContent.mobile-view-resultados .mapaColumn { opacity: 0; visibility: hidden; pointer-events: none; } + .resultadosColumn { padding: 0.5rem; padding-bottom: 50px; } + .mapaColumn .mapaComponenteContainer, .mapaColumn .mapaRenderArea { height: 100%; } + .panelPartidosContainer { padding-bottom: 0; } + .zoomControlsContainer, .mapaVolverBtn { top: 15px; } + .headerBottomRow { flex-direction: column; align-items: stretch; gap: 1rem; } + .municipioSearchContainer { min-width: 100%; } + + @media (max-width: 900px) and (orientation: landscape) { + .panelMainContent { display: flex; flex-direction: row; position: static; height: 85vh; min-height: 400px; } + .mapaColumn, + .resultadosColumn { position: static; height: auto; width: auto; opacity: 1; visibility: visible; pointer-events: auto; flex: 3; overflow-y: auto; } + .resultadosColumn { flex: 2; min-width: 300px; } + .mobileResultsCardContainer { display: none; } + .panelToggleBtn { display: flex; } + } +} + +.mobileResultsCardContainer { + position: absolute; + bottom: 0px; + left: 50%; + transform: translateX(-50%); + z-index: 40; + width: 95%; + max-width: 450px; + background-color: rgba(255, 255, 255, 0.95); + border-radius: 12px; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + border: 1px solid rgba(0, 0, 0, 0.1); + transition: all 0.3s ease-in-out; + display: flex; + flex-direction: column; +} +.mobileResultsCardContainer.view-resultados .collapsibleSection { display: none; } +.mobileResultsCardContainer.view-resultados .mobileCardViewToggle { border-top: none; } +.collapsibleSection { display: flex; flex-direction: column; } +.mobileResultsHeader { display: flex; justify-content: space-between; align-items: center; padding: 12px 18px; cursor: pointer; } +.mobileResultsHeader .headerInfo { display: flex; align-items: baseline; gap: 12px; } +.mobileResultsHeader .headerInfo h4 { margin: 0; font-size: 1.2rem; font-weight: 700; } +.mobileResultsHeader .headerInfo .headerActionText { font-size: 0.8rem; color: #6c757d; font-weight: 500; text-transform: uppercase; } +.mobileResultsHeader .headerToggleIcon { font-size: 1.5rem; color: #007bff; transition: transform 0.3s; } +.mobileResultsContent { max-height: 0; opacity: 0; overflow: hidden; transition: max-height 0.3s ease-in-out, opacity 0.3s ease-in-out, padding 0.3s ease-in-out; padding: 0 15px; border-top: 1px solid transparent; } +.mobileResultsCardContainer.expanded .mobileResultsContent { max-height: 500px; opacity: 1; padding: 5px 15px 15px 15px; border-top-color: #e0e0e0; } +.mobileResultRow { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-bottom: 1px solid #f0f0f0; border-left: 4px solid; padding-left: 8px; } +.mobileResultRow:last-child { border-bottom: none; } +.mobileResultLogo { flex-shrink: 0; width: 40px; height: 40px; border-radius: 8px; } +.mobileResultLogo img { width: 100%; height: 100%; border-radius: 8px; } +.mobileResultInfo { flex-grow: 1; min-width: 0; } +.mobileResultPartyName { display: block; font-weight: 600; font-size: 0.9rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.mobileResultCandidateName { display: block; font-size: 0.75rem; color: #6c757d; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.mobileResultStats { display: flex; flex-direction: column; align-items: flex-end; flex-shrink: 0; } +.mobileResultStats strong { font-size: 0.95rem; font-weight: 700; } +.mobileResultStats span { font-size: 0.7rem; color: #6c757d; } +.noResultsText { padding: 1rem; text-align: center; color: #6c757d; font-size: 0.9rem; } +.mobileCardViewToggle { display: flex; padding: 5px; background-color: rgba(230, 230, 230, 0.6); border-top: 1px solid rgba(0, 0, 0, 0.08); } +.mobileCardViewToggle .toggleBtn { flex: 1; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 10px 15px; border: none; background-color: transparent; border-radius: 25px; cursor: pointer; font-size: 1rem; font-weight: 500; color: #555; transition: all 0.2s ease-in-out; } +.mobileCardViewToggle .toggleBtn.active { background-color: #007bff; color: white; box-shadow: 0 2px 5px rgba(0, 123, 255, 0.2); } + +@media (max-width: 380px) { + .mobileResultsHeader { padding: 4px 10px; } + .mobileResultsHeader .headerInfo h4 { font-size: 0.75rem; text-transform: uppercase; } + .mobileResultsHeader .headerInfo .headerActionText { font-size: 0.7rem; } + .mobileCardViewToggle .toggleBtn { padding: 6px 10px; font-size: 0.8rem; } +} \ No newline at end of file diff --git a/Elecciones-Web/frontend/src/features/legislativas/nacionales/PanelNacionalWidget.tsx b/Elecciones-Web/frontend/src/features/legislativas/nacionales/PanelNacionalWidget.tsx index 3ccca55..da099fc 100644 --- a/Elecciones-Web/frontend/src/features/legislativas/nacionales/PanelNacionalWidget.tsx +++ b/Elecciones-Web/frontend/src/features/legislativas/nacionales/PanelNacionalWidget.tsx @@ -1,3 +1,5 @@ +// src/features/legislativas/nacionales/PanelNacionalWidget.tsx + import { useMemo, useState, Suspense, useEffect } from 'react'; import { useSuspenseQuery } from '@tanstack/react-query'; import { getPanelElectoral } from '../../../apiService'; @@ -5,7 +7,8 @@ import { MapaNacional } from './components/MapaNacional'; import { PanelResultados } from './components/PanelResultados'; import { Breadcrumbs } from './components/Breadcrumbs'; import { MunicipioSearch } from './components/MunicipioSearch'; -import './PanelNacional.css'; +// 1. La importación de CSS ahora se hace como un módulo +import styles from './PanelNacional.module.css'; import Select from 'react-select'; import type { PanelElectoralDto, ResultadoTicker } from '../../../types/types'; import { FiMap, FiList, FiChevronDown, FiChevronUp } from 'react-icons/fi'; @@ -26,22 +29,23 @@ interface MobileResultsCardProps { const formatPercent = (num: number) => `${(num || 0).toFixed(2).replace('.', ',')}%`; // --- SUB-COMPONENTE PARA UNA FILA DE RESULTADO --- +// 2. Todas las props 'className' ahora usan el objeto 'styles' const ResultRow = ({ partido }: { partido: ResultadoTicker }) => ( -
-
+
+
-
+
{partido.nombreCandidato ? ( <> - {partido.nombreCandidato} - {partido.nombreCorto || partido.nombre} + {partido.nombreCandidato} + {partido.nombreCorto || partido.nombre} ) : ( - {partido.nombreCorto || partido.nombre} + {partido.nombreCorto || partido.nombre} )}
-
+
{formatPercent(partido.porcentaje)} {partido.votos.toLocaleString('es-AR')}
@@ -80,44 +84,50 @@ const MobileResultsCard = ({ return null; } + // 3. Clases condicionales también se construyen con el objeto 'styles' + const cardClasses = [ + styles.mobileResultsCardContainer, + isExpanded ? styles.expanded : '', + styles[`view-${mobileView}`] + ].join(' '); + return ( -
+
{/* Sección Colapsable con Resultados */} -
-
setIsExpanded(!isExpanded)}> -
+
+
setIsExpanded(!isExpanded)}> +

{ambitoNombre}

- {/* Se añade una clase para estilizar este texto específicamente */} - {isExpanded ? 'Ocultar resultados' : 'Ver top 3'} + {isExpanded ? 'Ocultar resultados' : 'Ver top 3'}
-
+
{isExpanded ? : }
-
+
{topResults.length > 0 ? ( topResults.map(partido => ) ) : ( -

No hay resultados para esta selección.

+

No hay resultados para esta selección.

)}
{/* Footer Fijo con Botones de Navegación */} -
+
@@ -190,22 +200,28 @@ export const PanelNacionalWidget = ({ eleccionId }: PanelNacionalWidgetProps) => [categoriaId] ); + const mainContentClasses = [ + styles.panelMainContent, + !isPanelOpen ? styles.panelCollapsed : '', + isMobile ? styles[`mobile-view-${mobileView}`] : '' + ].join(' '); + return ( -
- -
-
+
+ +
+
'No se encontraron municipios'} />
diff --git a/Elecciones-Web/frontend/src/features/legislativas/nacionales/components/PanelResultados.tsx b/Elecciones-Web/frontend/src/features/legislativas/nacionales/components/PanelResultados.tsx index a0575fc..ca5b9be 100644 --- a/Elecciones-Web/frontend/src/features/legislativas/nacionales/components/PanelResultados.tsx +++ b/Elecciones-Web/frontend/src/features/legislativas/nacionales/components/PanelResultados.tsx @@ -5,6 +5,8 @@ import { assetBaseUrl } from '../../../../apiService'; import { AnimatedNumber } from './AnimatedNumber'; import { CircularProgressbar, buildStyles } from 'react-circular-progressbar'; import 'react-circular-progressbar/dist/styles.css'; +// 1. Importamos el archivo de estilos como un módulo CSS +import styles from '../PanelNacional.module.css'; const formatPercent = (num: number) => `${(num || 0).toFixed(2).replace('.', ',')}%`; const formatVotes = (num: number) => Math.round(num).toLocaleString('es-AR'); @@ -30,11 +32,12 @@ interface PanelResultadosProps { } export const PanelResultados = ({ resultados, estadoRecuento }: PanelResultadosProps) => { + // 2. Todas las props 'className' ahora usan el objeto 'styles' return ( -
+
-
-
+
+
Participación
-
+
-
+
{resultados.map(partido => (
-
+
-
-
-
+
+
+
{partido.nombreCandidato ? ( <> - {partido.nombreCandidato} - {partido.nombreCorto || partido.nombre} + {partido.nombreCandidato} + {partido.nombreCorto || partido.nombre} ) : ( - {partido.nombreCorto || partido.nombre} + {partido.nombreCorto || partido.nombre} )}
-
- +
+ - + votos
-
-
+
+
diff --git a/Elecciones-Web/frontend/src/features/legislativas/nacionales/components/PanelResultadosSkeleton.tsx b/Elecciones-Web/frontend/src/features/legislativas/nacionales/components/PanelResultadosSkeleton.tsx index 7534e0c..14212b3 100644 --- a/Elecciones-Web/frontend/src/features/legislativas/nacionales/components/PanelResultadosSkeleton.tsx +++ b/Elecciones-Web/frontend/src/features/legislativas/nacionales/components/PanelResultadosSkeleton.tsx @@ -1,21 +1,26 @@ // src/features/legislativas/nacionales/components/PanelResultadosSkeleton.tsx + +// 1. Importamos el archivo de estilos como un módulo CSS +import styles from '../PanelNacional.module.css'; + +// 2. Todas las props 'className' ahora usan el objeto 'styles' const SkeletonRow = () => ( -
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
+
); export const PanelResultadosSkeleton = () => ( -
+
{[...Array(5)].map((_, i) => )}
); \ No newline at end of file diff --git a/Elecciones-Web/frontend/src/features/legislativas/nacionales/components/ProvinciaCard.tsx b/Elecciones-Web/frontend/src/features/legislativas/nacionales/components/ProvinciaCard.tsx index 0394731..71b12ce 100644 --- a/Elecciones-Web/frontend/src/features/legislativas/nacionales/components/ProvinciaCard.tsx +++ b/Elecciones-Web/frontend/src/features/legislativas/nacionales/components/ProvinciaCard.tsx @@ -3,6 +3,8 @@ import type { ResumenProvincia, CategoriaResumen } from '../../../../types/types import { MiniMapaSvg } from './MiniMapaSvg'; import { ImageWithFallback } from '../../../../components/common/ImageWithFallback'; import { assetBaseUrl } from '../../../../apiService'; +// 1. Importamos el archivo de estilos como un módulo CSS +import styles from '../ResultadosNacionalesCardsWidget.module.css'; interface CategoriaDisplayProps { categoria: CategoriaResumen; @@ -17,48 +19,47 @@ interface ProvinciaCardProps { const formatNumber = (num: number) => num.toLocaleString('es-AR'); const formatPercent = (num: number) => `${num.toFixed(2).replace('.', ',')}%`; +// 2. Todas las props 'className' en este sub-componente ahora usan el objeto 'styles' const CategoriaDisplay = ({ categoria, mostrarBancas }: CategoriaDisplayProps) => { return ( -
-

{categoria.categoriaNombre}

+
+

{categoria.categoriaNombre}

{categoria.resultados.map(res => (
- {/* --- INICIO DE LA MODIFICACIÓN --- */} -
+
- {/* --- FIN DE LA MODIFICACIÓN --- */} -
+
{res.nombreCandidato ? ( <> - {res.nombreCandidato} - {res.nombreCortoAgrupacion || res.nombreAgrupacion} + {res.nombreCandidato} + {res.nombreCortoAgrupacion || res.nombreAgrupacion} ) : ( - {res.nombreCortoAgrupacion || res.nombreAgrupacion} + {res.nombreCortoAgrupacion || res.nombreAgrupacion} )} -
-
+
+
-
- {formatPercent(res.porcentaje)} - {formatNumber(res.votos)} votos +
+ {formatPercent(res.porcentaje)} + {formatNumber(res.votos)} votos
{mostrarBancas && ( -
+
+{res.bancasObtenidas} Bancas
@@ -66,7 +67,7 @@ const CategoriaDisplay = ({ categoria, mostrarBancas }: CategoriaDisplayProps) =
))} -