refactor: Migra todos los widgets nacionales a CSS Modules para encapsular estilos
Esta refactorización modifica la forma en que los widgets manejan sus estilos para prevenir conflictos con los CSS de los sitios anfitriones donde se incrustan. Se ha migrado el sistema de estilos de CSS global a CSS Modules para todos los componentes principales y sus hijos, asegurando que todas las clases sean únicas y estén aisladas. Cambios principales: - Se actualizan los componentes .tsx para importar y usar los módulos de estilos (`import styles from ...`). - Se renombran los archivos `.css` a `.module.css`. - Se añade una regla en cada módulo para proteger la `font-family` y el `box-sizing` del widget, evitando que sean sobreescritos por estilos externos. - Se ajustan los selectores para librerías de terceros (react-select, react-simple-maps) usando `:global()` para mantener la compatibilidad. - Se mueven las variables CSS de `:root` a las clases principales de cada widget para evitar colisiones en el scope global. Como resultado, los widgets (`HomeCarouselWidget`, `PanelNacionalWidget`, `ResultadosNacionalesCardsWidget`, `CongresoNacionalWidget`) son ahora más robustos, portátiles y visualmente consistentes en cualquier entorno.
This commit is contained in:
		| @@ -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); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user