diff --git a/app/(pages)/hack4her/page.tsx b/app/(pages)/hack4her/page.tsx index 2888075..8b8c53b 100644 --- a/app/(pages)/hack4her/page.tsx +++ b/app/(pages)/hack4her/page.tsx @@ -1,6 +1,7 @@ import Counter from "@/app/components/hack4her/countdown"; import SectionHack4Her from "@/app/components/hack4her/sectionHack4Her"; import Sponsor from "@/app/components/hack4her/secSponsor"; +import Section from "@/app/components/general/Section"; import Definition from "@/app/components/hack4her/QueEsHack4Her" import Scheme from "@/app/components/hack4her/schedule" import FAQS from '@/app/components/hack4her/textCarousel' @@ -11,8 +12,19 @@ import ConoceArca from "@/app/components/hack4her/colaborador"; const Hack4HerPage = () => { return ( <> +
+
+
+

+ Muy pronto… +

+
+
+
+ +
@@ -36,6 +48,7 @@ const Hack4HerPage = () => {
+ {/* Badge de MLH */} { +const ProjectShowcase: React.FC = () => { return (
+ +
-
-
- -
-
- - - -
); }; -export default ProyectosPage; +export default ProjectShowcase; diff --git a/app/(pages)/serviciosocial/page.tsx b/app/(pages)/serviciosocial/page.tsx index 35361bc..220cc84 100644 --- a/app/(pages)/serviciosocial/page.tsx +++ b/app/(pages)/serviciosocial/page.tsx @@ -1,55 +1,137 @@ -import Header2sub from "@/app/components/header2sub"; import Footer from "@/app/components/general/Footer"; -import Carousel from "@/app/components/carousel"; import Section from "@/app/components/general/Section"; -import TwoColumns from "@/app/components/twoColumns"; +import Banner from "@/app/components/serviciosocial/Banner"; +import ObjectiveMission from "@/app/components/serviciosocial/ObjectiveMission"; +import Timeline from "@/app/components/serviciosocial/Timeline"; +import Carousel from "@/app/components/serviciosocial/CarouselServicioSocial"; +import RolesGrid from "@/app/components/serviciosocial/RolesGrid"; +import StatsSection from "@/app/components/serviciosocial/StatsSection"; +import BenefitsList from "@/app/components/serviciosocial/BenefitsList"; +import CTASection from "@/app/components/serviciosocial/CTASection"; import React from "react"; +interface BannerData { + title: string; + highlightTitle: string; + description: string; + image: string; +} + +const bannerData = { + title: "Un Servicio Social con", + highlightTitle: "Impacto", + description: "Inspirando futuras líderes tech con WitCode", + image: "/images/serviciosocial/abajo_de_que_es_witcode.JPG" +}; + const Page = () => { return ( -
- {/* Header Section */} +
+ {/* Banner */} + + + {/* ¿Qué es WitCode? */} +
+
+ {/* Decorative elements */} +
+
+ +
+

+ ¿Qué es WitCode? +

+

+ Nuestro programa de servicio social enfocado en disminuir la brecha de género en tecnología + mediante educación accesible e inclusiva +

+ + + {/* Foto grupal */} +
+ Foto grupal WitCode +
+ +
+
+
+ + {/* ¿Cómo funciona? */} +
+ {/* Decorative pattern */} +
+
+
+ +
+
+

+ ¿Cómo funciona? +

+

+ Tu experiencia como tutor/a en WitCode +

+ + + {/* Carrusel de fotos */} +
+ +
+
+
+
+ + {/* Roles Disponibles */}
-
- +
+
+

+ Roles disponibles +

+

+ Encuentra tu forma de contribuir +

+ +
- {/* Carousel Section */} - + {/* Nuestro Impacto */} + - {/* TwoColumns Section */} + {/* Beneficios */}
- +
+ {/* Decorative gradient blobs */} +
+
+ +
+

+ Beneficios +

+

+ ¿Por qué unirte a WitCode? +

+ +
+
- {/* Footer Section */} -
+ {/* CTA Final */} + + + {/* Footer */} +
); }; -export default Page; +export default Page; \ No newline at end of file diff --git a/app/components/AnimatedPhotoGrid.tsx b/app/components/AnimatedPhotoGrid.tsx new file mode 100644 index 0000000..59350c0 --- /dev/null +++ b/app/components/AnimatedPhotoGrid.tsx @@ -0,0 +1,171 @@ +"use client"; + +import { useState, useEffect } from 'react'; + +export default function AnimatedPhotoGrid() { + const allPhotos: string[] = [ + '/images/home/home_1.JPG', + '/images/home/home_2.JPG', + '/images/home/home_3.JPG', + '/images/home/home_4.JPG', + '/images/home/home_5.JPG', + '/images/home/home_6.JPG', + '/images/home/home_7.JPG', + '/images/home/home_8.JPG', + '/images/home/home_9.JPG', + '/images/home/home_10.JPG', + '/images/home/home_11.JPG', + '/images/home/home_12.JPG', + '/images/home/home_13.JPG', + '/images/home/home_14.JPG', + '/images/home/home_15.JPG', + '/images/home/home_16.JPG', + '/images/home/home_17.JPG', + '/images/home/home_18.JPG', + '/images/home/home_19.JPG', + '/images/home/home_20.JPG', + '/images/home/home_21.JPG', + '/images/home/home_22.JPG', + '/images/home/home_23.JPG', + '/images/home/home_24.JPG', + '/images/home/home_25.JPG', + '/images/home/home_26.JPG', + '/images/home/home_27.JPG', + ]; + + const [photos, setPhotos] = useState([]); + + useEffect(() => { + const shuffled: string[] = [...allPhotos].sort(() => Math.random() - 0.5); + const selected: string[] = []; + + while (selected.length < 50) { + selected.push(...shuffled); + } + + setPhotos(selected.slice(0, 50)); + }, []); + + const positions = [ + // Fila 1 - arriba + { top: '3%', left: '0%', rotate: -5, size: 'w-56 h-44', zIndex: 12 }, + { top: '6%', left: '10%', rotate: 3, size: 'w-60 h-48', zIndex: 15 }, + { top: '2%', left: '20%', rotate: -2, size: 'w-56 h-44', zIndex: 10 }, + { top: '5%', left: '30%', rotate: 4, size: 'w-64 h-52', zIndex: 14 }, + { top: '3%', left: '41%', rotate: -3, size: 'w-56 h-44', zIndex: 11 }, + { top: '6%', left: '51%', rotate: 5, size: 'w-60 h-48', zIndex: 13 }, + { top: '4%', left: '61%', rotate: -4, size: 'w-56 h-44', zIndex: 16 }, + { top: '2%', left: '71%', rotate: 3, size: 'w-60 h-48', zIndex: 9 }, + { top: '5%', left: '81%', rotate: -5, size: 'w-56 h-44', zIndex: 14 }, + { top: '3%', left: '91%', rotate: 4, size: 'w-60 h-48', zIndex: 12 }, + + // Fila 2 + { top: '22%', left: '1%', rotate: 4, size: 'w-60 h-48', zIndex: 14 }, + { top: '19%', left: '11%', rotate: -3, size: 'w-56 h-44', zIndex: 12 }, + { top: '24%', left: '21%', rotate: 5, size: 'w-64 h-52', zIndex: 15 }, + { top: '20%', left: '32%', rotate: -2, size: 'w-56 h-44', zIndex: 10 }, + { top: '23%', left: '42%', rotate: 3, size: 'w-60 h-48', zIndex: 13 }, + { top: '21%', left: '52%', rotate: -4, size: 'w-56 h-44', zIndex: 16 }, + { top: '25%', left: '62%', rotate: 4, size: 'w-64 h-48', zIndex: 11 }, + { top: '22%', left: '73%', rotate: -5, size: 'w-56 h-44', zIndex: 14 }, + { top: '19%', left: '83%', rotate: 3, size: 'w-60 h-48', zIndex: 12 }, + { top: '23%', left: '93%', rotate: -3, size: 'w-56 h-44', zIndex: 15 }, + + // Fila 3 - medio + { top: '43%', left: '0%', rotate: -3, size: 'w-56 h-44', zIndex: 15 }, + { top: '40%', left: '10%', rotate: 5, size: 'w-60 h-48', zIndex: 12 }, + { top: '45%', left: '20%', rotate: -4, size: 'w-64 h-52', zIndex: 10 }, + { top: '41%', left: '31%', rotate: 3, size: 'w-56 h-44', zIndex: 14 }, + { top: '44%', left: '41%', rotate: -2, size: 'w-60 h-48', zIndex: 13 }, + { top: '42%', left: '51%', rotate: 4, size: 'w-56 h-44', zIndex: 16 }, + { top: '46%', left: '61%', rotate: -5, size: 'w-64 h-48', zIndex: 11 }, + { top: '43%', left: '72%', rotate: 3, size: 'w-56 h-44', zIndex: 15 }, + { top: '40%', left: '82%', rotate: -4, size: 'w-60 h-48', zIndex: 13 }, + { top: '44%', left: '92%', rotate: 5, size: 'w-56 h-44', zIndex: 10 }, + + // Fila 4 + { top: '64%', left: '1%', rotate: 4, size: 'w-60 h-48', zIndex: 12 }, + { top: '61%', left: '11%', rotate: -3, size: 'w-56 h-44', zIndex: 14 }, + { top: '66%', left: '21%', rotate: 5, size: 'w-64 h-52', zIndex: 11 }, + { top: '62%', left: '32%', rotate: -2, size: 'w-56 h-44', zIndex: 15 }, + { top: '65%', left: '42%', rotate: 3, size: 'w-60 h-48', zIndex: 13 }, + { top: '63%', left: '52%', rotate: -4, size: 'w-56 h-44', zIndex: 16 }, + { top: '67%', left: '62%', rotate: 5, size: 'w-64 h-48', zIndex: 10 }, + { top: '64%', left: '73%', rotate: -3, size: 'w-56 h-44', zIndex: 14 }, + { top: '61%', left: '83%', rotate: 4, size: 'w-60 h-48', zIndex: 12 }, + { top: '65%', left: '93%', rotate: -5, size: 'w-56 h-44', zIndex: 15 }, + + // Fila 5 + { top: '83%', left: '2%', rotate: -4, size: 'w-56 h-44', zIndex: 13 }, + { top: '80%', left: '12%', rotate: 3, size: 'w-60 h-48', zIndex: 11 }, + { top: '85%', left: '22%', rotate: -2, size: 'w-56 h-44', zIndex: 14 }, + { top: '81%', left: '32%', rotate: 5, size: 'w-64 h-52', zIndex: 16 }, + { top: '84%', left: '43%', rotate: -3, size: 'w-56 h-44', zIndex: 10 }, + { top: '82%', left: '53%', rotate: 4, size: 'w-60 h-48', zIndex: 15 }, + { top: '86%', left: '63%', rotate: -5, size: 'w-56 h-44', zIndex: 12 }, + { top: '83%', left: '73%', rotate: 3, size: 'w-64 h-48', zIndex: 14 }, + { top: '80%', left: '84%', rotate: -4, size: 'w-56 h-44', zIndex: 11 }, + { top: '84%', left: '94%', rotate: 5, size: 'w-60 h-48', zIndex: 13 }, + ]; + + return ( +
+ {photos.map((photo, index) => { + const position = positions[index]; + if (!position) return null; + + return ( +
+
+ {`WIT +
+
+ ); + })} +
+ +
+ ); +} \ No newline at end of file diff --git a/app/components/SponsorsCarousel.tsx b/app/components/SponsorsCarousel.tsx new file mode 100644 index 0000000..c9a0d58 --- /dev/null +++ b/app/components/SponsorsCarousel.tsx @@ -0,0 +1,120 @@ +'use client' + +import React, { useRef, useEffect, useState } from 'react'; + +export default function SponsorsCarousel() { + const scrollRef = useRef(null); + const [isPaused, setIsPaused] = useState(false); + const [scrollTimeout, setScrollTimeout] = useState(null); + + useEffect(() => { + const scrollContainer = scrollRef.current; + if (!scrollContainer) return; + + const handleScroll = () => { + + setIsPaused(true); + + if (scrollTimeout) { + clearTimeout(scrollTimeout); + } + + const timeout = setTimeout(() => { + setIsPaused(false); + }, 1000); + + setScrollTimeout(timeout); + + // Resetear scroll cuando llega al final + const maxScroll = scrollContainer.scrollWidth / 3; + if (scrollContainer.scrollLeft >= maxScroll) { + scrollContainer.scrollLeft = 0; + } + }; + + scrollContainer.addEventListener('scroll', handleScroll); + + return () => { + scrollContainer.removeEventListener('scroll', handleScroll); + if (scrollTimeout) clearTimeout(scrollTimeout); + }; + }, [scrollTimeout]); + + const logos: { src: string; alt: string }[] = [ + { src: "/images/LOGO_ARCA.png", alt: "Arca Continental" }, + { src: "/images/aliados/muchored_logo-removebg-preview.png", alt: "Mucho Red" }, + { src: "/images/aliados/LEGO.png", alt: "LEGO" }, + { src: "/images/aliados/Apex-systems.png", alt: "Apex Systems" }, + { src: "/images/aliados/Steelcase.png", alt: "Steelcase" }, + { src: "/images/aliados/interius_logo_azul.png", alt: "Interius" }, + { src: "/images/aliados/Carrier_logo.png", alt: "Carrier" }, + { src: "/images/aliados/Microplus_fondo-removebg-preview.png", alt: "Microplus" }, + { src: "/images/aliados/csoftmty_logo.png", alt: "CsoftMty" }, + { src: "/images/aliados/upnow_logo2.png", alt: "Upnow" }, + { src: "/images/aliados/clarios-logo2.png", alt: "Clarios" }, + ]; + + return ( +
+

+ Nuestros Aliados +

+ {/* Contenedor del carrusel infinito */} +
+
+
+ +
+
+ {/* Repetimos los logos 3 veces para el efecto infinito */} + {[1, 2, 3].map((group) => ( +
+ {logos.map((logo, idx) => ( +
+ {logo.alt} +
+ ))} +
+ ))} +
+
+
+ + +
+ ); +} \ No newline at end of file diff --git a/app/components/carousel.tsx b/app/components/carousel.tsx index f822713..3a3bf06 100644 --- a/app/components/carousel.tsx +++ b/app/components/carousel.tsx @@ -1,3 +1,4 @@ +//carousel.tsx 'use client' import React, { useState, useEffect } from 'react'; import { SlArrowLeft, SlArrowRight } from "react-icons/sl"; diff --git a/app/components/general/Logo.tsx b/app/components/general/Logo.tsx index 15a1861..eb26392 100644 --- a/app/components/general/Logo.tsx +++ b/app/components/general/Logo.tsx @@ -3,7 +3,7 @@ import Link from "next/link"; const Logo = () => { return ( - Logo + Logo ); }; diff --git a/app/components/general/Section.tsx b/app/components/general/Section.tsx index 8ed6526..993742e 100644 --- a/app/components/general/Section.tsx +++ b/app/components/general/Section.tsx @@ -1,3 +1,4 @@ +//Section.tsx import { ReactNode } from "react" const Section = ({children}: {children:ReactNode}) => { diff --git a/app/components/general/colors.css b/app/components/general/colors.css new file mode 100644 index 0000000..05dba4e --- /dev/null +++ b/app/components/general/colors.css @@ -0,0 +1,48 @@ + +/* paleta de colores WIT */ + +:root { + /* colores principales*/ + --principal-morado: #6411AD; + --principal-morado-10: #6411AD1A; + --principal-morado-20: #6411AD33; + --principal-morado-30: #6411AD4D; + + --principal-morado-claro: #B49CFF; + --principal-morado-claro-10: #B49CFF1A; + --principal-morado-claro-20: #B49CFF33; + --principal-morado-claro-30: #B49CFF4D; + + /* colores secundarios */ + --secundario-morado: #47126b; + --secundario-morado-10: #47126b1A; + --secundario-morado-20: #47126b33; + --secundario-morado-30: #47126b4D; + + --secundario-morado-claro: #c6c8ee; + --secundario-morado-claro-10: #c6c8ee1A; + --secundario-morado-claro-20: #c6c8ee33; + --secundario-morado-claro-30: #c6c8ee4D; + + --secundario-rosa: #ff5795; + --secundario-rosa-10: #ff57951A; + --secundario-rosa-20: #ff579533; + --secundario-rosa-30: #ff57954D; + + /*colores neutros */ + --neutro-negro: #000000; + --neutro-negro-10: #0000001A; + --neutro-negro-20: #00000033; + --neutro-negro-30: #0000004D; + + --neutro-gris: #2e2d2d; + --neutro-gris-10: #2e2d2d1A; + --neutro-gris-20: #2e2d2d33; + --neutro-gris-30: #2e2d2d4D; + + --neutro-blanco: #FFFFFF; + --neutro-blanco-10: #FFFFFF1A; + --neutro-blanco-20: #FFFFFF33; + --neutro-blanco-30: #FFFFFF4D; + +} \ No newline at end of file diff --git a/app/components/hack4her/challenges.tsx b/app/components/hack4her/challenges.tsx index b96e8cf..068daac 100644 --- a/app/components/hack4her/challenges.tsx +++ b/app/components/hack4her/challenges.tsx @@ -7,10 +7,10 @@ interface Challenge { } const challengesData: Challenge[] = [ - { title: 'DIME AI aplicado a la Operación', imageUrl: '/images/reto1.jpeg' }, - { title: 'Reinventando el acceso, simple, seguro y amigable.', imageUrl: '/images/reto2.jpeg' }, - { title: 'Predicción de fallas de Smart Coolers', imageUrl: '/images/reto3.jpeg' }, - { title: 'Live Loyalty Hack - Reembolso de Puntos en Tiempo Real', imageUrl: '/images/reto4.jpeg' } + { title: 'DIME AI aplicado a la Operación', imageUrl: '/images/hack4her/reto1.jpeg' }, + { title: 'Reinventando el acceso, simple, seguro y amigable.', imageUrl: '/images/hack4her/reto2.jpeg' }, + { title: 'Predicción de fallas de Smart Coolers', imageUrl: '/images/hack4her/reto3.jpeg' }, + { title: 'Live Loyalty Hack - Reembolso de Puntos en Tiempo Real', imageUrl: '/images/hack4her/reto4.jpeg' } ] const ChallengesSection: React.FC = () => ( diff --git a/app/components/header2sub.tsx b/app/components/header2sub.tsx index 1f2e806..07839dc 100644 --- a/app/components/header2sub.tsx +++ b/app/components/header2sub.tsx @@ -1,3 +1,4 @@ +//header2sub.tsx 'use client' import clsx from 'clsx' import React from 'react' @@ -29,16 +30,14 @@ const Header2sub: React.FC = ({ titulo, subtitulo, texto }) => {
-

+

{titulo} -

+ -

+

{subtitulo} -

- - -

+ +

{texto}

diff --git a/app/components/proyectos_com/NextProjectCard.css b/app/components/proyectos_com/NextProjectCard.css new file mode 100644 index 0000000..dbc8ab1 --- /dev/null +++ b/app/components/proyectos_com/NextProjectCard.css @@ -0,0 +1,166 @@ + +.next-project-card { + display: flex; + flex-direction: column; + background-color: var(--neutro-blanco); + border-radius: 0; + overflow: hidden; + margin-bottom: 2rem; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + transition: all 0.3s ease; + height: 450px; + width: 200; + border-radius: 2rem; +} + +.next-project-card:hover { + box-shadow: 0 8px 24px rgba(100, 17, 173, 0.15); + transform: translateY(-4px); +} + + +.next-project-image-container { + position: relative; + width: 100%; + height: 200px; + flex-shrink: 0; + overflow: hidden; +} + +.next-project-image { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.5s ease; +} + +.next-project-card:hover .next-project-image { + transform: scale(1.05); +} + +.date-overlay { + position: absolute; + top: 10px; + left: 20px; + background-color: var(--principal-morado); + color: var(--neutro-blanco); + padding: 1rem 1.5rem; + border-radius: 0; + text-align: center; + min-width: 80px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); + z-index: 10; +} + +.date-content { + display: flex; + flex-direction: column; + gap: 0.1rem; +} + +.date-day { + font-size: 2rem; + font-weight: 700; + line-height: 1; +} + +.date-month { + font-size: 1rem; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 1px; + opacity: 0.9; +} + +.next-project-content { + padding: 1.5rem; + display: flex; + flex-direction: column; + gap: 0.75rem; + flex: 1; +} + +.project-title { + font-size: 1.2rem; + font-weight: 700; + color: var(--principal-morado); + margin: 0; + line-height: 1.3; +} + +.separator { + width: 60px; + height: 3px; + background: linear-gradient(90deg, var(--principal-morado), var(--principal-morado-claro)); + border-radius: 2px; +} + + +.project-link-container { + margin-top: auto; + padding-top: 0.5rem; +} + + +.project-link { + display: inline-flex; + align-items: center; + gap: 0.5rem; + color: var(--principal-morado); + font-weight: 600; + font-size: 1rem; + text-decoration: none; + padding: 0.75rem 1.5rem; + border: 2px solid var(--principal-morado); + border-radius: 50px; + transition: all 0.3s ease; + background-color: transparent; + cursor: pointer; +} + +.project-link:hover { + background: var(--principal-morado); + color: var(--neutro-blanco); + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(100, 17, 173, 0.3); +} + + + + + +@media (min-width: 768px) { + .next-project-card { + min-height: 450px; + } + + .next-project-image-container { + height: 250px; + } + + .next-project-content { + padding: 2rem; + } + + .project-title { + font-size: 1.75rem; + } + + .project-description { + font-size: 1.125rem; + } + + .date-overlay { + top: 25px; + left: 25px; + padding: 1.25rem 1.75rem; + } + + .date-day { + font-size: 2.5rem; + } + + .date-month { + font-size: 1.125rem; + } +} \ No newline at end of file diff --git a/app/components/proyectos_com/NextProjectCard.tsx b/app/components/proyectos_com/NextProjectCard.tsx new file mode 100644 index 0000000..7b39ea5 --- /dev/null +++ b/app/components/proyectos_com/NextProjectCard.tsx @@ -0,0 +1,78 @@ +"use client"; +import React from "react"; +import Image from "next/image"; +import "./NextProjectCard.css"; +import Link from "next/link"; + +interface NextProject { + day: string; + month: string; + title: string; + image: string; + link?: string; + +} + +interface NextProjectCardProps { + project: NextProject; +} + +const NextProject: React.FC = ({ project }) => { + + const isExternalLink = project.link?.startsWith('http'); + const defaultLinkText = "Saber más"; + + return ( +
+
+ {project.title} + +
+
+ {project.day} + {project.month} +
+
+
+ + +
+

{project.title}

+ {project.link && ( +
+ {isExternalLink ? ( + + + {defaultLinkText} + + + ) : ( + + + {defaultLinkText} + + + )} +
+ )} +
+ +
+ ); +}; + +export default NextProject; \ No newline at end of file diff --git a/app/components/proyectos_com/ProjectCard.css b/app/components/proyectos_com/ProjectCard.css new file mode 100644 index 0000000..34a3d3e --- /dev/null +++ b/app/components/proyectos_com/ProjectCard.css @@ -0,0 +1,216 @@ +.project-card-wrapper { + margin-bottom: clamp(2rem, 4vw, 5rem); + border-radius: clamp(1rem, 2vw, 2rem); + overflow: hidden; + background: var(--principal-morado-claro-15); + box-shadow: 0 8px 32px rgba(50, 17, 173, 0.17); + border: 3px solid var(--principal-morado-10); + max-width: 100%; +} + +.project-card-wrapper:hover { + margin-bottom: clamp(2rem, 4vw, 5rem); + border-radius: clamp(1rem, 2vw, 2rem); + overflow: hidden; + background: var(--principal-morado-claro-20); + box-shadow: 0 8px 32px rgba(100, 17, 180, 0.30); + border: 3px solid var(--principal-morado); + max-width: 100%; + scale: 1.01; +} + +.project-card { + display: flex; + align-items: stretch; + flex-direction: column; + min-height: 0; + width: 100%; +} + +.slider-container { + height: clamp(200px, 35vh, 300px); + position: relative; + flex-shrink: 0; + overflow: hidden; +} + +.slider-container, +.slick-slider, +.slick-list, +.slick-track, +.slick-slide, +.slick-slide > div { + height: 100%; +} + +.slider-image { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} + +.slider-image:hover { + scale: 1.01; +} + +.slide-item { + width: 100%; + height: 100%; +} + +.text-container { + width: 100%; + text-align: center; + padding: clamp(1.25rem, 2.5vw, 2rem); + display: flex; + flex-direction: column; + box-sizing: border-box; + flex: 1; + min-height: 0; +} + +.project-title { + font-size: clamp(1.1rem, 3.5vw, 1.8rem); + font-weight: 500; + margin-bottom: 0.75rem; + line-height: 1.3; + background: linear-gradient(50deg, var(--principal-morado), var(--secundario-rosa)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + word-wrap: break-word; + overflow-wrap: break-word; +} + +.project-description { + color: var(--neutro-gris); + opacity: 0.85; + font-size: clamp(0.8rem, 2vw, 0.95rem); + line-height: 1.5; + margin: 0 0 1.25rem 0; + word-wrap: break-word; + overflow-wrap: break-word; + flex: 1; +} + +.project-title::after { + content: ''; + display: block; + width: 80px; + height: 3px; + background: linear-gradient(90deg, var(--principal-morado), var(--secundario-rosa)); + margin: 0.75rem auto; + border-radius: 2px; + opacity: 0.8; +} + +.stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); + gap: 0.75rem; + width: 100%; +} + +.stat-box { + background: linear-gradient(150deg, var(--principal-morado), var(--secundario-rosa)); + color: var(--neutro-blanco); + border-radius: 10px; + padding: 0.75rem 0.5rem; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + min-height: 70px; + box-shadow: 0 4px 12px rgba(100, 17, 173, 0.08); + box-sizing: border-box; +} + +.stat-box:hover { + transform: translateY(-4px); + box-shadow: 0 8px 20px rgba(100, 17, 173, 0.20); +} + +.number-stat .stat-value { + font-size: clamp(1.1rem, 3vw, 1.6rem); + font-weight: 700; + color: var(--neutro-blanco); + line-height: 1; + margin-bottom: 0.25rem; +} + +.number-stat .stat-label { + font-size: clamp(0.75rem, 1.8vw, 0.9rem); + color: var(--neutro-blanco); + line-height: 1.2; + font-weight: 500; + overflow-wrap: break-word; + word-wrap: break-word; + text-align: center; +} + +/*responsividad*/ + +@media (min-width: 768px) { + .project-card { + display: grid; + grid-template-columns: 45% 55%; + align-items: stretch; + } + + .slider-container { + width: 100%; + height: 100%; + } + + .slider-image { + height: 100%; + } + + .text-container { + text-align: left; + padding: 2rem; + max-width: 800px; + justify-self: start; + } + + .project-title::after { + margin: 0.75rem 0; + width: 100px; + } + + .project-description { + margin-bottom: 1.5rem; + } +} + +@media (max-width: 480px) { + .slider-container { + height: 180px; + } + + .text-container { + padding: 1.25rem; + } + + .stats-grid { + grid-template-columns: 1fr; + gap: 0.5rem; + } + + .stat-box { + min-height: 65px; + padding: 0.5rem; + } +} + +@media (min-width: 481px) and (max-width: 767px) { + .slider-container { + height: 220px; + } + + .stats-grid { + grid-template-columns: repeat(1, 1fr); + } +} diff --git a/app/components/proyectos_com/ProjectCard.tsx b/app/components/proyectos_com/ProjectCard.tsx new file mode 100644 index 0000000..bc054dc --- /dev/null +++ b/app/components/proyectos_com/ProjectCard.tsx @@ -0,0 +1,87 @@ +"use client"; +import React from "react"; +import Slider, { Settings } from "react-slick"; +import { useState } from "react"; +import "slick-carousel/slick/slick.css"; +import "slick-carousel/slick/slick-theme.css"; +import "./ProjectCard.css"; + +interface StatItem { + value: string; + label: string; + isNumber?: boolean; +} + +interface Project { + title: string; + description: string; + images: string[]; + stats?: StatItem[]; +} + +interface ProjectCardProps { + project: Project; +} + + +const ProjectCard: React.FC = ({ project }) => { + const settings: Settings = { + dots: false, + infinite: true, + speed: 500, + slidesToShow: 1, + slidesToScroll: 1, + arrows: false, + autoplay: true, + autoplaySpeed: 4000, + }; + + const shouldShowStats = project.stats; + + return ( +
+ +
+ + {/* Slider a la izquierda */} +
+ + {project.images.map((img, i) => ( +
+ {`${project.title} +
+ ))} +
+
+ + {/* Texto a la derecha */} +
+

{project.title}

+

{project.description}

+
+ {project.stats && project.stats.length > 0 && ( +
+ {project.stats.map((stat, index) => ( +
+
{stat.value}
+
{stat.label}
+
+ ))} +
+ )} +
+
+ +
+ + + +
+ ); +}; + +export default ProjectCard; \ No newline at end of file diff --git a/app/components/serviciosocial/Banner.tsx b/app/components/serviciosocial/Banner.tsx new file mode 100644 index 0000000..3bf042a --- /dev/null +++ b/app/components/serviciosocial/Banner.tsx @@ -0,0 +1,170 @@ +'use client' +import React, { useEffect, useRef } from 'react'; + +interface BannerData { + title: string; + highlightTitle: string; + description: string; + image: string; +} + +interface BannerProps { + bannerComp: BannerData; +} + +const Banner: React.FC = ({bannerComp}) => { + const particlesRef = useRef(null); + + useEffect(() => { + + if (particlesRef.current) { + const particleCount = 30; + for (let i = 0; i < particleCount; i++) { + const particle = document.createElement('div'); + particle.className = 'absolute w-1 h-1 bg-white/30 rounded-full'; + particle.style.left = Math.random() * 100 + '%'; + particle.style.animationDelay = Math.random() * 15 + 's'; + particle.style.animationDuration = (Math.random() * 10 + 10) + 's'; + particle.style.animation = 'floatParticle 15s infinite ease-in-out'; + particlesRef.current.appendChild(particle); + } + } + }, []); + + const scrollToAbout = () => { + const aboutSection = document.getElementById('about-section'); + aboutSection?.scrollIntoView({ behavior: 'smooth' }); + }; + + return ( +
+ {/* Img de fondo */} +
+ + {/* Overlay oscuro*/} +
+ + {/* Otro overlay */} +
+ + {/* Gradiente radial anim */} +
+ + {/* Figs decorativas */} +
+
+ + {/* Particulas */} +
+ + {/* Contenido */} +
+

+ {bannerComp.title} {bannerComp.highlightTitle} +

+

+ {bannerComp.description} +

+
+ + {/* Indicador de scroll */} +
+ + + +
+ + +
+ ); +}; + +export default Banner; diff --git a/app/components/serviciosocial/BenefitsList.tsx b/app/components/serviciosocial/BenefitsList.tsx new file mode 100644 index 0000000..807e484 --- /dev/null +++ b/app/components/serviciosocial/BenefitsList.tsx @@ -0,0 +1,63 @@ +'use client' +import React from 'react'; + +const BenefitsList = () => { + const benefits = [ + { + title: "Horas oficiales de servicio social", + description: "Cumple con tu servicio mientras generas impacto real" + }, + { + title: "Desarrollo de habilidades", + description: "Liderazgo, comunicación, enseñanza y trabajo en equipo" + }, + { + title: "Impacto en la comunidad", + description: "Contribuye a cerrar la brecha de género en tech" + }, + { + title: "Networking", + description: "Conecta con mujeres apasionadas por la tecnología" + }, + { + title: "Refuerza tus conocimientos", + description: "Repasa y profundiza temas técnicos al enseñarlos" + } + ]; + + return ( +
+ {benefits.map((benefit, index) => ( +
+ {/* Animated border effect */} +
+ + {/* Background accent */} +
+ + {/* Check Icon */} +
+ + + +
+ + {/* Content */} +
+ + {benefit.title} + +

+ {benefit.description} +

+
+
+ ))} +
+ ); +}; + +export default BenefitsList; \ No newline at end of file diff --git a/app/components/serviciosocial/CTASection.tsx b/app/components/serviciosocial/CTASection.tsx new file mode 100644 index 0000000..9dc16af --- /dev/null +++ b/app/components/serviciosocial/CTASection.tsx @@ -0,0 +1,81 @@ +'use client' +import React from 'react'; + +const CTASection = () => { + return ( +
+ {/* Animated Background blobs */} +
+
+ + {/* Decorative grid pattern */} +
+
+
+ +
+

+ ¡Únete a la comunidad WitCode! +

+

+ Ayúdanos a disminuir la brecha de género. Apoya e impulsa a las futuras mujeres de México en tech. +

+ + + +

+ ¿Tienes dudas? Escríbenos a @witcode.mty +

+
+ + +
+ ); +}; + +export default CTASection; \ No newline at end of file diff --git a/app/components/serviciosocial/CarouselServicioSocial.tsx b/app/components/serviciosocial/CarouselServicioSocial.tsx new file mode 100644 index 0000000..cac4f96 --- /dev/null +++ b/app/components/serviciosocial/CarouselServicioSocial.tsx @@ -0,0 +1,185 @@ +'use client' +import React, { useState, useEffect, useRef } from 'react'; + +const CarouselServicioSocial = () => { + const slides = [ + { + url: 'images/serviciosocial/servicio_social_carousel1.JPG' + }, + { + url: 'images/serviciosocial/servicio_social_carousel2.JPG' + }, + { + url: 'images/serviciosocial/servicio_social_carousel3.JPG' + }, + { + url: 'images/serviciosocial/servicio_social_carousel4.JPG' + }, + ]; + + const [currentSlide, setCurrentSlide] = useState(0); + const [isAutoPlay, setIsAutoPlay] = useState(true); + const [direction, setDirection] = useState<'left' | 'right'>('right'); + const autoPlayRef = useRef(null); + + const nextSlide = () => { + setDirection('right'); + setCurrentSlide((prev) => (prev + 1) % slides.length); + }; + + const prevSlide = () => { + setDirection('left'); + setCurrentSlide((prev) => (prev - 1 + slides.length) % slides.length); + }; + + const goToSlide = (index: number) => { + setDirection(index > currentSlide ? 'right' : 'left'); + setCurrentSlide(index); + }; + + useEffect(() => { + if (isAutoPlay) { + autoPlayRef.current = setInterval(() => { + nextSlide(); + }, 5000); + } + + return () => { + if (autoPlayRef.current) { + clearInterval(autoPlayRef.current); + } + }; + }, [currentSlide, isAutoPlay]); + + // Keyboard navigation + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === 'ArrowLeft') { + handlePrev(); + } else if (e.key === 'ArrowRight') { + handleNext(); + } + }; + + window.addEventListener('keydown', handleKeyDown); + return () => window.removeEventListener('keydown', handleKeyDown); + }, []); + + const handleMouseEnter = () => setIsAutoPlay(false); + const handleMouseLeave = () => setIsAutoPlay(true); + + const handlePrev = () => { + prevSlide(); + setIsAutoPlay(false); + setTimeout(() => setIsAutoPlay(true), 1000); + }; + + const handleNext = () => { + nextSlide(); + setIsAutoPlay(false); + setTimeout(() => setIsAutoPlay(true), 1000); + }; + + return ( +
+ {/* Main Carousel Container with Gradient Border */} +
+
+ {/* Slides Container */} +
+ {slides.map((slide, index) => { + const isActive = index === currentSlide; + const isPrev = index === (currentSlide - 1 + slides.length) % slides.length; + const isNext = index === (currentSlide + 1) % slides.length; + + return ( +
+ {`WitCode + + {/* Subtle Purple Tint Overlay */} +
+
+ ); + })} +
+ + {/* Navigation Buttons - Enhanced */} + + + + + {/* Slide Counter */} +
+ {currentSlide + 1} / {slides.length} +
+
+
+ + {/* Enhanced Progress Bar Navigation */} +
+ {slides.map((_, index) => ( + + ))} +
+
+ ); +}; + +export default CarouselServicioSocial; \ No newline at end of file diff --git a/app/components/serviciosocial/ObjectiveMission.tsx b/app/components/serviciosocial/ObjectiveMission.tsx new file mode 100644 index 0000000..c7b754d --- /dev/null +++ b/app/components/serviciosocial/ObjectiveMission.tsx @@ -0,0 +1,68 @@ +'use client' +import React from 'react'; + +const ObjectiveMission = () => { + return ( +
+ {/* Objetivo Card */} +
+ {/* Background gradient effect */} +
+ + {/* Decorative corner */} +
+ + {/* Icon Container */} +
+
+ + + +
+
+ + {/* Title */} +

+ Objetivo +

+ + {/* Description */} +

+ Atender la brecha de género en la tecnología brindando herramientas educativas que nivelen + las oportunidades de manera igualitaria en este ámbito. +

+
+ + {/* Misión Card */} +
+ {/* Background gradient effect */} +
+ + {/* Decorative corner */} +
+ + {/* Icon Container */} +
+
+ + + +
+
+ + {/* Title */} +

+ Misión +

+ + {/* Description */} +

+ Promover e inspirar el uso de la tecnología mediante talleres prácticos y dinámicos + dirigidos a alumnas de 1° a 3° de secundaria de la escuela Ciudad de los Niños. +

+
+
+ ); +}; + +export default ObjectiveMission; \ No newline at end of file diff --git a/app/components/serviciosocial/RolesGrid.tsx b/app/components/serviciosocial/RolesGrid.tsx new file mode 100644 index 0000000..1e4ea90 --- /dev/null +++ b/app/components/serviciosocial/RolesGrid.tsx @@ -0,0 +1,69 @@ +'use client' +import React from 'react'; + +const RolesGrid = () => { + const roles = [ + { + icon: ( + + {/* Grupo de personas/equipo para Coordinadores */} + + + + + + ), + title: "Coordinadores", + description: "Organizan las sesiones, gestionan equipos y aseguran el correcto funcionamiento del programa." + }, + { + icon: ( + + {/* Persona presentando/enseñando para Instructores */} + + + + + + ), + title: "Instructores", + description: "Preparan y presentan el módulo asignado, guían a las alumnas durante los retos prácticos." + } + ]; + + return ( +
+ {roles.map((role, index) => ( +
+ {/* Background gradient effect */} +
+ + {/* Decorative corner */} +
+ + {/* Icon Container */} +
+
+ {role.icon} +
+
+ + {/* Title */} +

+ {role.title} +

+ + {/* Description */} +

+ {role.description} +

+
+ ))} +
+ ); +}; + +export default RolesGrid; \ No newline at end of file diff --git a/app/components/serviciosocial/StatsSection.tsx b/app/components/serviciosocial/StatsSection.tsx new file mode 100644 index 0000000..59bb5fa --- /dev/null +++ b/app/components/serviciosocial/StatsSection.tsx @@ -0,0 +1,118 @@ +'use client' +import React, { useState, useEffect, useRef } from 'react'; + +const StatsSection = () => { + const [isVisible, setIsVisible] = useState(false); + const [counts, setCounts] = useState({ alumnas: 0, tutores: 0, permanencia: 0 }); + const sectionRef = useRef(null); + + const stats = [ + { key: 'alumnas', target: 94, label: 'Alumnas participantes', suffix: '' }, + { key: 'tutores', target: 76, label: 'Tutores en servicio social', suffix: '' }, + { key: 'permanencia', target: 90, label: 'Tasa de permanencia', suffix: '%' } + ]; + + useEffect(() => { + const observer = new IntersectionObserver( + ([entry]) => { + if (entry.isIntersecting && !isVisible) { + setIsVisible(true); + } + }, + { threshold: 0.3 } + ); + + if (sectionRef.current) { + observer.observe(sectionRef.current); + } + + return () => observer.disconnect(); + }, [isVisible]); + + useEffect(() => { + if (!isVisible) return; + + const duration = 2000; // 2 seconds + const steps = 60; + const interval = duration / steps; + + const timers = stats.map((stat) => { + let currentCount = 0; + const increment = stat.target / steps; + + return setInterval(() => { + currentCount += increment; + if (currentCount >= stat.target) { + setCounts((prev) => ({ ...prev, [stat.key]: stat.target })); + clearInterval(timers[stats.indexOf(stat)]); + } else { + setCounts((prev) => ({ ...prev, [stat.key]: Math.floor(currentCount) })); + } + }, interval); + }); + + return () => timers.forEach(clearInterval); + }, [isVisible]); + + return ( +
+ {/* Background decorative elements */} +
+
+ +
+

+ Nuestro Impacto +

+

+ En cifras totales del 2024 +

+ +
+ {stats.map((stat, index) => ( +
+ {/* Shimmer effect */} +
+ + {/* Decorative corner */} +
+ +
+
+ {counts[stat.key as keyof typeof counts]}{stat.suffix} +
+
+ {stat.label} +
+
+
+ ))} +
+
+ + +
+ ); +}; + +export default StatsSection; \ No newline at end of file diff --git a/app/components/serviciosocial/Timeline.tsx b/app/components/serviciosocial/Timeline.tsx new file mode 100644 index 0000000..8a8f527 --- /dev/null +++ b/app/components/serviciosocial/Timeline.tsx @@ -0,0 +1,115 @@ +'use client' +import React from 'react'; + +const Timeline = () => { + const timelineItems = [ + { + icon: ( + + + + + + + + ), + title: "Sesiones Semanales", + items: [ + "Sábados a las 10:00 AM", + "Duración aproximada: 2.5 horas", + "Formato híbrido: tutores presenciales, alumnas pueden estar en línea" + ] + }, + { + icon: ( + + + + + ), + title: "Estructura de Sesión", + items: [ + "10:00 AM - Inicio conjunto y presentación del módulo", + "12:00 PM - Equipos pequeños para retos prácticos", + "12:30 PM - Presentación de proyectos por equipos", + "Sistema de gamificación: equipos acumulan puntos" + ] + }, + { + icon: ( + + + + + + + ), + title: "Dos Niveles", + content: ( + <> +

+ Principiantes: Para alumnas nuevas. Algoritmos y diagramas de flujo, Scratch, Java y Python básico. +

+

+ Avanzadas: Para alumnas con experiencia. Programación Orientada a Objetos en Python, Ciencia de Datos, HTML y CSS, Javascript, Introducción a APIs. +

+ + ) + } + ]; + + return ( +
+ {timelineItems.map((item, index) => ( +
+ {/* Vertical Line */} + {index !== timelineItems.length - 1 && ( +
+ )} + + {/* Icon Circle */} +
+
+
{item.icon}
+
+ + {/* Content Card */} +
+

+ {item.title} +

+ {item.items ? ( +
    + {item.items.map((listItem, idx) => ( +
  • + + {listItem} +
  • + ))} +
+ ) : ( +
+ {item.content} +
+ )} +
+
+ ))} + + +
+ ); +}; + +export default Timeline; \ No newline at end of file diff --git a/app/components/showcase.tsx b/app/components/showcase.tsx new file mode 100644 index 0000000..ce76c17 --- /dev/null +++ b/app/components/showcase.tsx @@ -0,0 +1,88 @@ +import React, { useState } from "react"; +import Slider, { Settings } from "react-slick"; +import "slick-carousel/slick/slick.css"; +import "slick-carousel/slick/slick-theme.css"; + +interface Project { + title: string; + description: string; + images: string[]; +} + +const projects: Project[] = [ + { + title: "Conferencias motivacionales", + description: + "El grupo invita al alumnado a una serie de conferencias y talleres de diferentes temas motivacionales y sobre experiencias de mujeres dentro y fuera del área de ingeniería.", + images: ["/images/proyectos/proy6.jpg", "/images/proyectos/proy6_2.jpg"], + }, + { + title: "Journey to Internship", + description: + "Serie de conferencias y talleres impartidos por empresas reconocidas para preparar a estudiantes para internships.", + images: ["/images/proyectos/JTI24_5.JPG", "/images/proyectos/JTI24_2.JPG"], + }, + { + title: "Desayuno del día de la mujer", + description: + "Desayuno conmemorativo donde alumnas, docentes y profesionales dialogan sobre experiencias y liderazgo femenino.", + images: ["/images/proyectos/desayuno.JPG"], + }, +]; + +// Componente para una sola tarjeta de proyecto +const ProjectCard: React.FC<{ project: Project }> = ({ project }) => { + const [activeIndex, setActiveIndex] = useState(0); + + const settings: Settings = { + dots: true, + infinite: true, + speed: 500, + slidesToShow: 1, + slidesToScroll: 1, + arrows: true, + autoplay: true, + autoplaySpeed: 4000, + beforeChange: (_current, next) => setActiveIndex(next), + }; + + return ( +
+ {/* Slider de imágenes */} +
+ + {project.images.map((img, i) => ( +
+ {project.title} +
+ ))} +
+
+ + {/* Texto */} +
+

+ {project.title} +

+

{project.description}

+
+
+ ); +}; + +// Componente que renderiza todas las tarjetas +const ProjectShowcase: React.FC = () => { + return ( +
+ {projects.map((project, i) => ( + + ))} +
+ ); +}; + +export default ProjectShowcase; diff --git a/app/components/twoColumns.tsx b/app/components/twoColumns.tsx index 4239066..beaf4b5 100644 --- a/app/components/twoColumns.tsx +++ b/app/components/twoColumns.tsx @@ -1,3 +1,4 @@ +//twoColumns.tsx import React from "react"; interface Column { diff --git a/app/layout.tsx b/app/layout.tsx index fa54786..5e3b806 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,6 +1,7 @@ import type { Metadata } from 'next' import { Inter } from 'next/font/google' import './globals.css' +import '@/app/components/general/colors.css' import Nav from './components/Nav/Nav' const inter = Inter({ subsets: ['latin'] }) @@ -16,8 +17,8 @@ export default function RootLayout({ children: React.ReactNode }) { return ( - - + +