├── .DS_Store ├── .gitignore ├── ConseguirTrabajoTI ├── README.md └── entrevistas │ ├── backend.md │ ├── frontend.md │ ├── index.md │ ├── qa.md │ └── ux-ui.md ├── PrimeraPaginaWeb ├── README.md ├── assets │ ├── css │ │ └── styles.css │ └── img │ │ ├── .DS_Store │ │ ├── desktop │ │ ├── image-footer.jpg │ │ ├── image-hero-left.png │ │ ├── image-hero-right.png │ │ ├── image-man-texting.jpg │ │ ├── image-men-in-meeting.jpg │ │ ├── image-woman-in-videocall.jpg │ │ └── image-women-videochatting.jpg │ │ ├── logo.svg │ │ ├── mobile │ │ └── image-footer.jpg │ │ └── tablet │ │ ├── image-footer.jpg │ │ └── image-hero.png ├── favicon-32x32.png └── index.html ├── ProgramacionPython ├── README.md ├── ejercicio_final_taller.ipynb ├── presentacion.pdf └── spotify-2023.csv ├── README.md ├── TallerAngular ├── .editorconfig ├── .gitignore ├── README.md ├── angular.json ├── package.json ├── src │ ├── app │ │ ├── app.component.html │ │ ├── app.component.scss │ │ ├── app.component.ts │ │ ├── app.config.ts │ │ ├── app.routes.ts │ │ ├── components │ │ │ ├── card-poke │ │ │ │ ├── card-poke.component.html │ │ │ │ ├── card-poke.component.scss │ │ │ │ └── card-poke.component.ts │ │ │ ├── fail-poke │ │ │ │ ├── fail-poke.component.html │ │ │ │ ├── fail-poke.component.scss │ │ │ │ └── fail-poke.component.ts │ │ │ ├── header │ │ │ │ ├── header.component.html │ │ │ │ ├── header.component.scss │ │ │ │ └── header.component.ts │ │ │ ├── loader │ │ │ │ ├── loader.component.html │ │ │ │ ├── loader.component.scss │ │ │ │ └── loader.component.ts │ │ │ ├── modal-poke │ │ │ │ ├── modal-poke.component.html │ │ │ │ ├── modal-poke.component.scss │ │ │ │ └── modal-poke.component.ts │ │ │ └── navbar │ │ │ │ ├── navbar.component.html │ │ │ │ ├── navbar.component.scss │ │ │ │ └── navbar.component.ts │ │ ├── models │ │ │ └── pokedex.model.ts │ │ └── views │ │ │ └── home │ │ │ ├── home.component.html │ │ │ ├── home.component.scss │ │ │ └── home.component.ts │ ├── assets │ │ └── images │ │ │ ├── poke-logo.png │ │ │ └── pokeball.png │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ └── styles.scss ├── tsconfig.app.json ├── tsconfig.json └── tsconfig.spec.json ├── TallerGraphql ├── .gitignore ├── MaterialDeApoyo.md ├── Presentacion.pdf ├── README.md ├── package-lock.json ├── package.json ├── src │ ├── data │ │ └── pokedex.json │ ├── main.ts │ └── schema │ │ └── index.ts └── tsconfig.json ├── TallerNode ├── .gitignore ├── README.md ├── index.js ├── models │ └── pokemon.model.js ├── normal_IMG_2503.webp ├── package-lock.json ├── package.json └── services │ ├── pokemon.service.factory.js │ ├── pokemon.service.js │ └── pokemonMongo.service.js ├── TallerRankingNode ├── backend │ ├── .env.example │ ├── .gitignore │ ├── docker-compose.yml │ ├── package-lock.json │ ├── package.json │ └── src │ │ ├── config │ │ └── constants.js │ │ ├── controllers │ │ └── ranking.controller.js │ │ ├── db │ │ ├── dao │ │ │ ├── memory │ │ │ │ └── ranking.dao.js │ │ │ ├── mongo │ │ │ │ ├── connection.js │ │ │ │ ├── models │ │ │ │ │ └── record.js │ │ │ │ └── ranking.dao.js │ │ │ └── ranking.dao.factory.js │ │ ├── dto │ │ │ └── record.dto.js │ │ └── ranking.repository.js │ │ ├── middlewares │ │ └── auth.middleware.js │ │ ├── routers │ │ └── ranking.router.js │ │ ├── server.js │ │ └── services │ │ └── ranking.service.js └── frontend │ ├── .env.local.example │ ├── .eslintrc.json │ ├── .gitignore │ ├── GUID.txt │ ├── ProjectVersion.txt │ ├── README.md │ ├── app │ ├── Score.tsx │ ├── favicon.ico │ ├── globals.css │ ├── layout.tsx │ └── page.tsx │ ├── components.json │ ├── components │ └── ui │ │ ├── alert-dialog.tsx │ │ └── button.tsx │ ├── dependencies.txt │ ├── lib │ └── utils.ts │ ├── next.config.mjs │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── public │ ├── Build │ │ ├── WebGL Builds.data │ │ ├── WebGL Builds.framework.js │ │ ├── WebGL Builds.loader.js │ │ └── WebGL Builds.wasm │ ├── StreamingAssets │ │ └── UnityServicesProjectConfiguration.json │ ├── TemplateData │ │ ├── favicon.ico │ │ ├── fullscreen-button.png │ │ ├── progress-bar-empty-dark.png │ │ ├── progress-bar-empty-light.png │ │ ├── progress-bar-full-dark.png │ │ ├── progress-bar-full-light.png │ │ ├── style.css │ │ ├── unity-logo-dark.png │ │ ├── unity-logo-light.png │ │ └── webgl-logo.png │ ├── next.svg │ └── vercel.svg │ ├── tailwind.config.ts │ └── tsconfig.json ├── TallerReact ├── Escuela de React.pdf ├── MaterialDeApoyo.md ├── README.md └── pokedex-app │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── public │ └── vite.svg │ ├── src │ ├── assets │ │ ├── Image_not_available.png │ │ └── react.svg │ ├── components │ │ ├── Header.jsx │ │ └── PokemonCard.jsx │ ├── main.jsx │ ├── routes │ │ ├── PokemonDetails.element.jsx │ │ ├── PokemonDetails.loader.js │ │ ├── Root.element.jsx │ │ └── Root.loader.js │ ├── services │ │ ├── getPokemon.js │ │ └── getPokemonList.js │ └── utils │ │ └── capitalizeWord.js │ └── vite.config.js └── TallerVue ├── Escuela de Vue - Techschool v2.pdf ├── README.md └── poke-battle ├── .eslintrc.cjs ├── .gitignore ├── .vscode └── extensions.json ├── README.md ├── index.html ├── jsconfig.json ├── package.json ├── public └── favicon.ico ├── src ├── App.vue ├── api │ └── index.js ├── assets │ └── main.css ├── components │ └── PokemonCard.vue ├── composables │ └── usePokemon.js ├── main.js └── services │ └── pokemon.services.js ├── vite.config.js └── yarn.lock /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | ProgramacionPython/.DS_Store 3 | TallerReact/pokedex-app/node_modules -------------------------------------------------------------------------------- /ConseguirTrabajoTI/README.md: -------------------------------------------------------------------------------- 1 | # Taller: Conseguir trabajo en tecnologías de la información: evaluación de portafolios y CV 2 | 3 | **Mentor de esta edición:** Eduardo Esteban Álvarez Castañeda 4 | 5 | - LinkedIn: [👾 Eduardo Álvarez Castañeda](https://linkedin.com/in/eduardoalvarezc) 6 | - Curriculum vitae: [eduardoalvarez.dev](https://resume.eduardoalvarez.dev/) 7 | - Redes sociales: [proskynete.dev](https://proskynete.dev) 8 | 9 | **Ayudante**: Argenis Matos 10 | 11 | - LinkedIn: [Argenis José Matos Matute](https://www.linkedin.com/in/argenis-matos) 12 | - Curriculum Vitae: [Argenis Mato](https://flowcv.com/resume/f6mskqkw9h) 13 | 14 | ## Descripción del Taller 15 | 16 | Aprende a optimizar tu CV y portafolio para el sector tecnológico con retroalimentación experta. En este taller, te proporcionaremos herramientas, consejos y buenas prácticas para que puedas destacar y mejorar tus posibilidades al postular a trabajos en el sector de TI. 17 | 18 | ## Objetivo del Taller 19 | 20 | El objetivo principal de este taller es que, al finalizar, los participantes tengan un CV y/o portafolio optimizado y ajustado a las necesidades y expectativas del mercado tecnológico actual. 21 | 22 | ## Prerrequisitos 23 | 24 | - Tener una versión actual de tu CV y/o portafolio. 25 | - Contar con una laptop para seguir las actividades prácticas. 26 | 27 | ## Material de apoyo 28 | 29 | - [Tips](https://github.com/JSConfCL/techschool/tree/main/ConseguirTrabajoTI/entrevistas/index.md) 30 | - [Flow CV](https://flowcv.com) 31 | 32 | --- 33 | 34 | En esta carpeta encontrarás todos los archivos, documentos y materiales necesarios para seguir el taller. Te recomendamos descargar y revisar estos materiales previamente para aprovechar al máximo la experiencia de aprendizaje. 35 | 36 | Esperamos que disfrutes del taller y que este material te sea de utilidad. Si tienes alguna duda o comentario, no dudes en dejar un issue en este repositorio o ponerte en contacto con el mentor de esta edición. 37 | 38 | ¡Buena suerte y feliz aprendizaje! 39 | -------------------------------------------------------------------------------- /ConseguirTrabajoTI/entrevistas/backend.md: -------------------------------------------------------------------------------- 1 | # Backend 2 | 3 | Veremos algunas de las preguntas que podrías encontrarte al momento de presentarte ante una entrevista de trabajo para el cargo de Backend Junior. Esto no quiere decir que sean las únicas, pero si serán las preguntas que considero importantes. 4 | 5 | Estas preguntas son sobre tecnologías web, sin pensar en lenguajes en específico, ya que lo más probable, es que te pidan realizar un ejercicio técnico con las tecnologías que la empresa usa. 6 | 7 | ## Preguntas tipo 8 | 9 | **¿Puedes describir alguna experiencia previa en desarrollo backend?** 10 | _Responde proporcionando una descripción de tu experiencia laboral, proyectos personales o académicos relacionados con el desarrollo backend._ 11 | 12 | --- 13 | 14 | **¿Cuál es la diferencia entre un servidor web y un servidor de aplicaciones?** 15 | _Explica que un servidor web maneja solicitudes HTTP y puede servir archivos estáticos, mientras que un servidor de aplicaciones ejecuta aplicaciones dinámicas y procesa lógica de negocio._ 16 | 17 | --- 18 | 19 | **¿Cuál es tu lenguaje de programación preferido para el desarrollo backend y por qué?** 20 | _Habla sobre el lenguaje que prefieres, como Node.js, Python, Java, etc., y menciona tus razones para elegirlo.._ 21 | 22 | --- 23 | 24 | **¿Puedes explicar qué es una API RESTful?** 25 | _Una API RESTful es un conjunto de rutas y métodos HTTP que permiten a los clientes acceder y manipular recursos a través de HTTP. Explica los conceptos de recursos, métodos y URIs._ 26 | 27 | --- 28 | 29 | **¿Cuál es la importancia de la seguridad en el desarrollo backend y cómo manejas la autenticación y autorización?** 30 | _Habla sobre cómo implementas medidas de seguridad, como la validación de datos de entrada, la autenticación de usuarios y la autorización para garantizar la seguridad en tu aplicación._ 31 | 32 | --- 33 | 34 | **¿Qué es una base de datos SQL y en qué se diferencia de una base de datos NoSQL?** 35 | _Explica que las bases de datos SQL son relacionales y utilizan tablas, mientras que las bases de datos NoSQL son no relacionales y utilizan diferentes estructuras de datos._ 36 | 37 | --- 38 | 39 | **¿Qué es la inyección de dependencias y cómo se implementa en un marco de trabajo?** 40 | _La inyección de dependencias es un patrón de diseño que se utiliza para gestionar las dependencias de un componente. Explica cómo se implementa en un marco de trabajo, como Spring (Java) o Angular (TypeScript)._ 41 | 42 | --- 43 | 44 | **¿Cuál es el propósito de las pruebas de unidad y cómo las llevas a cabo?** 45 | _Las pruebas de unidad se realizan para validar el comportamiento de una unidad de código. Habla sobre cómo creas pruebas de unidad y utilizas herramientas como JUnit o pytest_ 46 | 47 | --- 48 | 49 | **¿Cómo manejarías la escalabilidad de una aplicación backend?** 50 | _Describe cómo abordarías la escalabilidad utilizando técnicas como la implementación de microservicios, balanceo de carga y escalabilidad horizontal._ 51 | 52 | --- 53 | 54 | **¿Has trabajado en entornos ágiles o colaborado con equipos multidisciplinarios?** 55 | _Si tienes experiencia en entornos ágiles o equipos multidisciplinarios, menciona cómo colaboraste y contribuiste en proyectos conjuntos._ 56 | -------------------------------------------------------------------------------- /ConseguirTrabajoTI/entrevistas/frontend.md: -------------------------------------------------------------------------------- 1 | # Frontend 2 | 3 | Veremos algunas de las preguntas que podrías encontrarte al momento de presentarte ante una entrevista de trabajo para el cargo de Frontend Junior. Esto no quiere decir que sean las únicas, pero si serán las preguntas que considero importantes. 4 | 5 | Estas preguntas son sobre tecnologías web, sin pensar en librerías o frameworks. Ya que lo más probable, es que te pidan realizar un ejercicio técnico con las tecnologías que la empresa usa. 6 | 7 | ## Preguntas tipo 8 | 9 | **¿Puedes describir alguna experiencia previa en desarrollo frontend?** 10 | _Responde proporcionando una descripción de tu experiencia laboral, proyectos personales o académicos relacionados con el desarrollo frontend._ 11 | 12 | --- 13 | 14 | **¿Cuál es la diferencia entre HTML, CSS y JavaScript?** 15 | _Explica brevemente las funciones de HTML (estructura), CSS (estilo) y JavaScript (comportamiento) en el desarrollo web._ 16 | 17 | --- 18 | 19 | **¿Qué es un framework y en que se diferencia con una librería? ¿Has trabajado con alguno?** 20 | _Una librería te permite solucionar un problema concreto, mientras que un framework te brinda un set de herramientas para desarrollar sistemas o aplicaciones._ 21 | 22 | --- 23 | 24 | **¿Qué es el responsive design y por qué es importante?** 25 | _Responde explicando que el responsive design se refiere a la adaptación de una página web a diferentes dispositivos y tamaños de pantalla para brindar una experiencia consistente a los usuarios._ 26 | 27 | --- 28 | 29 | **¿Cómo gestionas la carga y la optimización de recursos en una página web para mejorar el rendimiento?** 30 | _Describe cómo optimizas imágenes, minimizas archivos CSS y JavaScript, y utilizas técnicas de carga diferida (lazy loading) para mejorar el rendimiento._ 31 | 32 | --- 33 | 34 | **¿Puedes explicar qué son las Promises en JavaScript?** 35 | _Explica que las Promises son objetos que representan un valor futuro o un posible error en una operación asincrónica._ 36 | 37 | --- 38 | 39 | **¿Qué son las Progressive Web Apps (PWAs) y cuáles son sus beneficios?** 40 | _Una PWA permite optimizar un sitio web para convertirlo al formato de una aplicación que podrá ser usada tanto en el móvil como en el escritorio del ordenador._ 41 | 42 | --- 43 | 44 | **¿Qué es el DOM y cómo interactúas con él en JavaScript?** 45 | _El Document Object Model (DOM) es una representación de la estructura de un documento HTML. Habla sobre cómo JavaScript puede manipular el DOM para realizar cambios dinámicos en una página web._ 46 | 47 | --- 48 | 49 | **¿Cómo garantizas la accesibilidad en tus proyectos frontend?** 50 | _Describe cómo sigues las pautas de accesibilidad, como el uso de atributos alt en imágenes y la inclusión de etiquetas semánticas en HTML, para que tus proyectos sean accesibles para personas con discapacidades._ 51 | 52 | --- 53 | 54 | **¿Has trabajado en equipos ágiles o colaborado con diseñadores y desarrolladores backend?** 55 | _Si tienes experiencia en entornos de desarrollo ágil o en equipos multidisciplinarios, menciona cómo colaboraste y contribuiste en proyectos conjuntos._ 56 | 57 | --- 58 | 59 | **¿Cuál es el propósito de CORS y cómo lo manejas en el desarrollo frontend?** 60 | _CORS (Cross-Origin Resource Sharing) es un mecanismo de seguridad en navegadores web. Explica cómo puedes configurar encabezados CORS en el lado del servidor y cómo tratarías problemas de origen cruzado en JavaScript._ 61 | -------------------------------------------------------------------------------- /ConseguirTrabajoTI/entrevistas/index.md: -------------------------------------------------------------------------------- 1 | # Preparando mi primera entrevista de trabajo 2 | 3 | A continuación veremos algunas de las típicas preguntas que nos podrían preguntar cuando nos enfrentamos a nuestras primeras entrevistas laborales. Algunas pueden variar dependiendo de la empresa, de la tecnología que estén solicitando, otros factores. 4 | 5 | ### Puntos a recordar: 6 | 7 | - Mantén la calma siempre, confía en tus conocimientos. 8 | - Es mucho mejor decir _”No se la respuesta, pero la puedo investigar”_, a intentar inventar una. Créeme, eso se nota y no ayuda mucho. 9 | - Probablemente te rechacen muchas veces, pero no te desanimes. **TU PUEDES!** 10 | 11 | ### Recursos 12 | 13 | - [Frontend](https://github.com/JSConfCL/techschool/tree/main/ConseguirTrabajoTI/entrevistas/frontend.md) 14 | - [Backend](https://github.com/JSConfCL/techschool/tree/main/ConseguirTrabajoTI/entrevistas/backend.md) 15 | - [QA](https://github.com/JSConfCL/techschool/tree/main/ConseguirTrabajoTI/entrevistas/qa.md) 16 | - [UX-UI](https://github.com/JSConfCL/techschool/tree/main/ConseguirTrabajoTI/entrevistas/ux-ui.md) 17 | -------------------------------------------------------------------------------- /ConseguirTrabajoTI/entrevistas/qa.md: -------------------------------------------------------------------------------- 1 | # Quality Assurance 2 | 3 | Veremos algunas de las preguntas que podrías encontrarte al momento de presentarte ante una entrevista de trabajo para el cargo de QA Junior. Esto no quiere decir que sean las únicas, pero si serán las preguntas que considero importantes. 4 | 5 | Estas preguntas son sobre el rol que cumple un QA en una empresa, sin pensar en un lenguaje o framework en específico, ya que lo más probable, es que te pidan realizar un ejercicio técnico con las tecnologías y/o herramientas que la empresa usa 6 | 7 | ## Preguntas tipo 8 | 9 | **¿Cuál es tu comprensión del rol de un QA en el desarrollo de software?** 10 | _Explica que un QA se encarga de garantizar la calidad del software al identificar defectos, realizar pruebas y asegurarse de que cumple con los requisitos y estándares de calidad._ 11 | 12 | --- 13 | 14 | **¿Cómo defines una buena prueba de software?** 15 | _Una buena prueba de software debe ser reproducible, específica, exhaustiva, y debe revelar defectos en el software._ 16 | 17 | --- 18 | 19 | **¿Cuál es tu proceso para documentar y rastrear defectos?** 20 | _Explica cómo registras los defectos utilizando una herramienta de seguimiento, incluyendo detalles como pasos para reproducir, prioridad y estado._ 21 | 22 | --- 23 | 24 | **¿Cuáles son los tipos de pruebas que conoces?** 25 | _Menciona pruebas como pruebas unitarias, pruebas de integración, pruebas de sistema, pruebas de regresión y pruebas de aceptación, y explica brevemente en qué consisten._ 26 | 27 | --- 28 | 29 | **¿Qué es la automatización de pruebas y cuándo es apropiado utilizarla?** 30 | _La automatización de pruebas se refiere a la escritura de scripts para realizar pruebas de forma automatizada. Es apropiado utilizarla cuando se realizan pruebas repetitivas o cuando se necesita una respuesta rápida en un ciclo de desarrollo ágil._ 31 | 32 | --- 33 | 34 | **¿Cómo manejarías una situación en la que encuentras un error crítico en el software antes del lanzamiento?** 35 | _Describe que informarías inmediatamente al equipo de desarrollo, registrarías el error en un sistema de seguimiento y colaborarías para encontrar una solución antes del lanzamiento._ 36 | 37 | --- 38 | 39 | **¿Qué es la prueba de carga y por qué es relevante en el control de calidad?** 40 | _La prueba de carga implica evaluar cómo se comporta el software bajo cargas de trabajo pesadas. Es relevante para garantizar que la aplicación sea escalable y funcione de manera eficiente bajo alta demanda._ 41 | 42 | --- 43 | 44 | **¿Cómo evaluarías la cobertura de pruebas en un proyecto y qué métricas utilizarías para medirla?** 45 | _Menciona el uso de métricas de cobertura de código y la revisión de los requisitos del proyecto para asegurarse de que se hayan realizado pruebas en todas las áreas críticas._ 46 | 47 | --- 48 | 49 | **¿Cómo seleccionas qué pruebas automatizar y cuáles hacer manualmente?** 50 | _Explica que se automatizan las pruebas que son repetitivas y críticas, mientras que las pruebas exploratorias y ad hoc se realizan manualmente._ 51 | 52 | --- 53 | 54 | **¿Has trabajado en equipos ágiles o con metodologías de desarrollo específicas?** 55 | _Si tienes experiencia en equipos ágiles, menciona cómo contribuiste en la planificación y ejecución de pruebas dentro de ese marco de trabajo._ 56 | -------------------------------------------------------------------------------- /ConseguirTrabajoTI/entrevistas/ux-ui.md: -------------------------------------------------------------------------------- 1 | # UX-UI 2 | 3 | Veremos algunas de las preguntas que podrías encontrarte al momento de presentarte ante una entrevista de trabajo para el cargo de UX-UI Junior. Esto no quiere decir que sean las únicas, pero si serán las preguntas que considero importantes. 4 | 5 | Estas preguntas son sobre diseño y mejoras de usabilidad, sin pensar en en específico, ya que lo más probable, es que te pidan realizar un ejercicio técnico con las tecnologías y/o herramientas que la empresa usa. 6 | 7 | ## Preguntas tipo 8 | 9 | **¿Puedes describir tu experiencia previa en diseño de experiencia de usuario (UX) y diseño de interfaz de usuario (UI)?** 10 | _Proporciona una descripción de tu experiencia laboral, proyectos personales o académicos relacionados con el diseño UX/UI._ 11 | 12 | --- 13 | 14 | **¿Cuál es la diferencia entre UX y UI design?** 15 | _Explica que el diseño de experiencia de usuario (UX) se centra en la experiencia y usabilidad del usuario, mientras que el diseño de interfaz de usuario (UI) se refiere al aspecto visual y la presentación de la interfaz._ 16 | 17 | --- 18 | 19 | **¿Cuál es tu proceso de diseño desde la investigación hasta la implementación?** 20 | _Describe tus pasos típicos, como investigación de usuarios, diseño de prototipos, pruebas de usabilidad y colaboración con desarrolladores._ 21 | 22 | --- 23 | 24 | **¿Cómo garantizas que tus diseños sean accesibles para todos los usuarios, incluyendo aquellos con discapacidades?** 25 | _Habla sobre cómo sigues las pautas de accesibilidad, como las WCAG, y cómo integras características accesibles en tus diseños._ 26 | 27 | --- 28 | 29 | **¿Qué herramientas de diseño y prototipado utilizas y por qué?** 30 | _Menciona las herramientas que utilizas, como Figma, Sketch, o Adobe XD, y explica por qué las consideras adecuadas para tu flujo de trabajo._ 31 | 32 | --- 33 | 34 | **¿Cómo abordarías el diseño de una interfaz de usuario para una aplicación móvil versus un sitio web?** 35 | _Habla sobre las diferencias en tamaño de pantalla, interacción táctil y navegación entre dispositivos móviles y sitios web._ 36 | 37 | --- 38 | 39 | **¿Puedes describir un proyecto en el que enfrentaste desafíos de diseño y cómo los superaste?** 40 | _Cuéntales sobre un proyecto en el que enfrentaste dificultades, cómo las identificaste y cómo resolviste los problemas._ 41 | 42 | --- 43 | 44 | **¿Qué es el diseño responsivo y cuál es su importancia?** 45 | _El diseño responsivo se refiere a la adaptación de una interfaz a diferentes tamaños de pantalla. Habla de su importancia para ofrecer una experiencia óptima en varios dispositivos._ 46 | 47 | --- 48 | 49 | **¿Cómo recopilas retroalimentación de los usuarios y la utilizas para mejorar tus diseños?** 50 | _Describe métodos como pruebas de usabilidad, encuestas y análisis de datos de usuario para recopilar retroalimentación y cómo la aplicas en las iteraciones de diseño._ 51 | 52 | --- 53 | 54 | **¿Has trabajado en equipos multidisciplinarios o colaborado estrechamente con desarrolladores? ¿Cómo fue tu experiencia?** 55 | _Si tienes experiencia en equipos multidisciplinarios, habla sobre cómo colaboraste y cómo tu trabajo de UX/UI se integró en el desarrollo del producto._ 56 | -------------------------------------------------------------------------------- /PrimeraPaginaWeb/README.md: -------------------------------------------------------------------------------- 1 | # Taller: Crear tu primera página web con Bootstrap y subirla a GitHub Pages 2 | 3 | **Mentor de esta edición:** [Nombre del Mentor] 4 | 5 | ## Descripción del Taller 6 | En este taller, te sumergirás en los fundamentos del diseño web utilizando Bootstrap, uno de los frameworks más populares y versátiles del mercado. No solo aprenderás a diseñar una página web desde cero, sino que también te enseñaremos a alojarla de forma gratuita en GitHub Pages, permitiéndote compartir tu creación con el mundo. 7 | 8 | ## Objetivo del Taller 9 | El principal objetivo de este taller es que, al final, cada participante tenga su propia página web personalizada y alojada en GitHub Pages, demostrando así sus habilidades iniciales en diseño web y despliegue. 10 | 11 | ## Prerrequisitos 12 | - Contar con una cuenta activa en GitHub. 13 | - Tener una laptop con un editor de texto instalado (recomendamos [VS Code](https://code.visualstudio.com/)). 14 | 15 | ## Material de apoyo 16 | Dentro de esta carpeta hallarás todos los archivos, plantillas y recursos que te ayudarán a desarrollar tu página web. Te sugerimos descargar y familiarizarte con estos materiales antes del taller para aprovechar al máximo la sesión. 17 | 18 | --- 19 | 20 | Esperamos que disfrutes y saques provecho de este taller. Si te surge alguna inquietud o pregunta, no dudes en crear un issue en este repositorio o comunicarte con el mentor de esta edición. 21 | 22 | ¡Adelante con ese proyecto web! 23 | -------------------------------------------------------------------------------- /PrimeraPaginaWeb/assets/css/styles.css: -------------------------------------------------------------------------------- 1 | .bg-purple { 2 | background-color: #8560b1; 3 | border-color: #8560b1; 4 | } 5 | .bg-purple:hover { 6 | background-color: #a174d7; 7 | } 8 | 9 | .bg-teal { 10 | background-color: #4d96a9; 11 | border-color: #4d96a9; 12 | } 13 | .bg-teal:hover { 14 | background-color: #5eb7cf; 15 | } 16 | 17 | .text-purple { 18 | color: #8560b1; 19 | } 20 | 21 | .text-teal { 22 | color: #4d96a9; 23 | } 24 | 25 | .vertical-divider { 26 | height: 70px; 27 | width: 50%; 28 | border-right: solid 1px #efefef; 29 | } 30 | 31 | .max-w-700 { 32 | max-width: 700px; 33 | } 34 | 35 | .footer-content { 36 | background-image: url("../img//desktop/image-footer.jpg"); 37 | background-position: center; 38 | background-repeat: no-repeat; 39 | background-size: cover; 40 | position: absolute; 41 | width: 100%; 42 | top: -30px; 43 | z-index: -2; 44 | } 45 | 46 | .footer-transparent { 47 | position: absolute; 48 | background-color: rgba(77, 150, 169, 0.8); 49 | width: 100%; 50 | height: 100%; 51 | top: 0; 52 | left: 0; 53 | z-index: -1; 54 | } 55 | -------------------------------------------------------------------------------- /PrimeraPaginaWeb/assets/img/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/PrimeraPaginaWeb/assets/img/.DS_Store -------------------------------------------------------------------------------- /PrimeraPaginaWeb/assets/img/desktop/image-footer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/PrimeraPaginaWeb/assets/img/desktop/image-footer.jpg -------------------------------------------------------------------------------- /PrimeraPaginaWeb/assets/img/desktop/image-hero-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/PrimeraPaginaWeb/assets/img/desktop/image-hero-left.png -------------------------------------------------------------------------------- /PrimeraPaginaWeb/assets/img/desktop/image-hero-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/PrimeraPaginaWeb/assets/img/desktop/image-hero-right.png -------------------------------------------------------------------------------- /PrimeraPaginaWeb/assets/img/desktop/image-man-texting.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/PrimeraPaginaWeb/assets/img/desktop/image-man-texting.jpg -------------------------------------------------------------------------------- /PrimeraPaginaWeb/assets/img/desktop/image-men-in-meeting.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/PrimeraPaginaWeb/assets/img/desktop/image-men-in-meeting.jpg -------------------------------------------------------------------------------- /PrimeraPaginaWeb/assets/img/desktop/image-woman-in-videocall.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/PrimeraPaginaWeb/assets/img/desktop/image-woman-in-videocall.jpg -------------------------------------------------------------------------------- /PrimeraPaginaWeb/assets/img/desktop/image-women-videochatting.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/PrimeraPaginaWeb/assets/img/desktop/image-women-videochatting.jpg -------------------------------------------------------------------------------- /PrimeraPaginaWeb/assets/img/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PrimeraPaginaWeb/assets/img/mobile/image-footer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/PrimeraPaginaWeb/assets/img/mobile/image-footer.jpg -------------------------------------------------------------------------------- /PrimeraPaginaWeb/assets/img/tablet/image-footer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/PrimeraPaginaWeb/assets/img/tablet/image-footer.jpg -------------------------------------------------------------------------------- /PrimeraPaginaWeb/assets/img/tablet/image-hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/PrimeraPaginaWeb/assets/img/tablet/image-hero.png -------------------------------------------------------------------------------- /PrimeraPaginaWeb/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/PrimeraPaginaWeb/favicon-32x32.png -------------------------------------------------------------------------------- /PrimeraPaginaWeb/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 12 | 13 | Meet Landing Page 14 | 15 | 16 |
17 |
18 | 19 |
20 | 21 |
22 | 27 |
28 |

29 | Group Chat
30 | for Everyone 31 |

32 |

33 | Meet makes it easy to connect with others face-to-face
34 | virtually and collaborate across any device. 35 |

36 |
37 | 40 | 43 |
44 |
45 | 46 |
49 |
50 |
51 | 56 |
57 |
58 |

59 | Group Chat
60 | for Everyone 61 |

62 |

63 | Meet makes it easy to connect with others face-to-face
64 | virtually and collaborate across any device. 65 |

66 |
67 | 70 | 73 |
74 |
75 |
76 | 81 |
82 |
83 |
84 | 85 |
86 |
87 |
88 | 89 | 01 90 | 91 |
92 |
93 | 94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | 102 |
103 |
104 |
Built for modern use
105 |

Smarter meetings, all in one place

106 |

Send messages, share files, show your screen, and record your meetings - all in one workspace. Control who can join with invite-only team access, data encryption, and data export.

107 |
108 |
109 |
110 | 111 |
112 |
113 |
114 | 115 | 02 116 | 117 |
118 |
119 | 120 | 141 | 142 |
143 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /ProgramacionPython/README.md: -------------------------------------------------------------------------------- 1 | # Taller: Programación básica con Python y análisis y visualización de datos básico 2 | 3 | **Mentor de esta edición:** Francisca Beatriz Medina Concha (frani.be) 4 | 5 | ## Descripción del Taller 6 | 7 | Sumérgete de lleno en el mundo de Python, el análisis y visualización de datos en este taller práctico. Con la ayuda de ejercicios prácticos y la potente herramienta online Google Colab, podrás trabajar con Python sin instalaciones, lo que te facilitará aún más adentrarte en los fundamentos de la programación, el análisis y visualización de datos. 8 | 9 | ## Objetivo principal 10 | 11 | El objetivo principal de este taller es que cada participante se familiarice con Python y con las herramientas básicas para el análisis y visualización de datos. Al final, cada uno debería ser capaz de realizar visualizaciones básicas de datos, todo ello alojado y guardado en Google Colab. 12 | 13 | ## Objetivos específicos 14 | 15 | - Adquirir conocimiento básicos en programación con Python. 16 | - Manejar y analizar datos con Pandas. 17 | - Crear de visualizaciones con Altair. 18 | 19 | ## Prerrequisitos 20 | 21 | - Contar con conocimientos básicos de programación. 22 | - Tener una cuenta activa de Google para acceder a [Google Colab](https://colab.research.google.com/). 23 | 24 | ## Material de apoyo 25 | 26 | En esta carpeta encontrarás archivos, guías y recursos que te guiarán a lo largo del taller. Te recomendamos descargar y revisar estos materiales previamente para maximizar tu experiencia durante la sesión. 27 | 28 | - [Presentación PDF](./presentacion.pdf) 29 | - [Presentación Drive](https://docs.google.com/presentation/d/1Dy7KeI5iXTUTuBoeHUAevqRsPXC-WepBnyOQaDhEt-A/edit?usp=sharing) 30 | - [Base de datos para ejercicio final](./spotify-2023.csv) 31 | - [Código utilizado para ejercicio final](./ejercicio_final_taller.ipynb) 32 | 33 | --- 34 | 35 | Esperamos que este taller te ofrezca una experiencia enriquecedora y te acerque más al mundo del análisis y visualización de datos con Python. Si tienes dudas o inquietudes, no dudes en abrir un issue en este repositorio o contactar directamente al mentor de esta edición. 36 | 37 | ¡Que tu curiosidad por los datos te guíe! 38 | -------------------------------------------------------------------------------- /ProgramacionPython/presentacion.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/ProgramacionPython/presentacion.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Español 2 | 3 | # Repositorio para TechSchool 4 | 5 | ¡Bienvenidos al repositorio oficial de **TechSchool**! 6 | 7 | Este espacio ha sido creado con el objetivo de proporcionar a los estudiantes todos los materiales y archivos necesarios para nuestros talleres. Dentro de este repositorio, encontrarás las carpetas correspondientes a cada uno de los talleres que ofrecemos en nuestros eventos. 8 | 9 | **TechSchool** es la evolución de los eventos NodeSchool y es organizado por la comunidad JavaScript Chile. Nuestro primer evento se celebra el [Fecha del Evento, ej: 28 de octubre de 2023] y estamos emocionados de compartir conocimientos y experiencias con todos los participantes. 10 | 11 | Te invitamos a explorar las carpetas, descargar el material y prepararte para una experiencia educativa enriquecedora. ¡Nos vemos en TechSchool! 12 | 13 | ### English 14 | 15 | # Repository for TechSchool 16 | 17 | Welcome to the official **TechSchool** repository! 18 | 19 | This space has been created to provide students with all the necessary materials and files for our workshops. Within this repository, you'll find all folders corresponding to each of the workshops we offer at the events. 20 | 21 | **TechSchool** is the evolution of the NodeSchool events and is organized by the JavaScript Chile community. Our first event is being held on [Event Date, e.g., October 28th, 2023], and we are excited to share knowledge and experiences with all participants. 22 | 23 | We invite you to explore the folders, download the material, and get ready for a rich educational experience. See you at TechSchool! 24 | -------------------------------------------------------------------------------- /TallerAngular/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /TallerAngular/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /bazel-out 8 | 9 | # Node 10 | /node_modules 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # IDEs and editors 15 | .idea/ 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # Visual Studio Code 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | .history/* 30 | 31 | # Miscellaneous 32 | /.angular/cache 33 | .sass-cache/ 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | testem.log 38 | /typings 39 | 40 | # System files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /TallerAngular/README.md: -------------------------------------------------------------------------------- 1 | # Taller: Desarrollando una Pokedex Interactiva con Angular 2 | 3 | **Mentor de esta edición:** Gonzalo Fleming G. [@gonzafg2](https://github.com/gonzafg2) 4 | 5 | ## Descripción del Taller 6 | 7 | Adéntrate en el mundo de Angular creando una Pokédex interactiva. Explora a tus Pokémon favoritos de la primera generación y descubre sus detalles. 8 | 9 | ## Objetivo del Taller 10 | 11 | - Conocer los conceptos básicos de Angular. 12 | - Crear una aplicación web interactiva. 13 | - Aprender a utilizar Bootstrap para darle estilo a la aplicación. 14 | - Aprender a consumir una API REST. 15 | - Aprender a desplegar una aplicación en GitHub Pages. 16 | - Aprender a utilizar Git y GitHub para el control de versiones. 17 | - Aprender a utilizar Angular CLI para crear y desplegar aplicaciones. 18 | 19 | ## Prerrequisitos 20 | 21 | - Laptop con acceso a un editor de texto. 22 | - Conocimientos básicos de Javascript, HTML y CSS. 23 | - Tener instalado Node.js y npm en tu laptop. 24 | - Tener instalado Git en tu laptop y cuenta activa en GitHub. 25 | - Tener instalado Angular CLI en tu laptop. 26 | 27 | ## Material de apoyo 28 | 29 | - Documentación oficial de Node.js: 30 | - Documentación oficial de npm: 31 | - Documentación oficial de Git: 32 | - Documentación oficial de GitHub: 33 | - Documentación oficial de Angular CLI: 34 | - Nueva documentación oficial de Angular: 35 | - Documentación oficial de Bootstrap: 36 | 37 | ## Recursos 38 | 39 | - API REST de Pokémon: 40 | 41 | ## Instrucciones 42 | 43 | 1. Clona este repositorio en tu laptop. 44 | 2. Crea un nuevo repositorio en tu cuenta de GitHub. 45 | 3. Cambia el origen del repositorio clonado a tu nuevo repositorio. 46 | 4. Descarga las dependencias del proyecto con `npm install`. 47 | 5. Completa los ejercicios propuestos por el mentor. 48 | 6. Despliega tu aplicación en GitHub Pages. 49 | 7. Comparte tu aplicación con tus compañeros y el mentor. 50 | 8. ¡Diviértete y disfruta del taller! 51 | 9. No olvides dejar tu estrella en el repositorio del mentor. 52 | 10. No olvides dejar tu estrella en este repositorio. 53 | 54 | ## Licencia 55 | 56 | [MIT](https://opensource.org/licenses/MIT) 57 | -------------------------------------------------------------------------------- /TallerAngular/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "pokedex-angular17": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "style": "scss" 11 | } 12 | }, 13 | "root": "", 14 | "sourceRoot": "src", 15 | "prefix": "app", 16 | "architect": { 17 | "build": { 18 | "builder": "@angular-devkit/build-angular:application", 19 | "options": { 20 | "outputPath": "dist/pokedex-angular17", 21 | "index": "src/index.html", 22 | "browser": "src/main.ts", 23 | "polyfills": [ 24 | "zone.js" 25 | ], 26 | "tsConfig": "tsconfig.app.json", 27 | "inlineStyleLanguage": "scss", 28 | "assets": [ 29 | "src/favicon.ico", 30 | "src/assets" 31 | ], 32 | "styles": [ 33 | "src/styles.scss" 34 | ], 35 | "scripts": [] 36 | }, 37 | "configurations": { 38 | "production": { 39 | "budgets": [ 40 | { 41 | "type": "initial", 42 | "maximumWarning": "500kb", 43 | "maximumError": "1mb" 44 | }, 45 | { 46 | "type": "anyComponentStyle", 47 | "maximumWarning": "2kb", 48 | "maximumError": "4kb" 49 | } 50 | ], 51 | "outputHashing": "all" 52 | }, 53 | "development": { 54 | "optimization": false, 55 | "extractLicenses": false, 56 | "sourceMap": true 57 | } 58 | }, 59 | "defaultConfiguration": "production" 60 | }, 61 | "serve": { 62 | "builder": "@angular-devkit/build-angular:dev-server", 63 | "configurations": { 64 | "production": { 65 | "buildTarget": "pokedex-angular17:build:production" 66 | }, 67 | "development": { 68 | "buildTarget": "pokedex-angular17:build:development" 69 | } 70 | }, 71 | "defaultConfiguration": "development" 72 | }, 73 | "extract-i18n": { 74 | "builder": "@angular-devkit/build-angular:extract-i18n", 75 | "options": { 76 | "buildTarget": "pokedex-angular17:build" 77 | } 78 | }, 79 | "test": { 80 | "builder": "@angular-devkit/build-angular:karma", 81 | "options": { 82 | "polyfills": [ 83 | "zone.js", 84 | "zone.js/testing" 85 | ], 86 | "tsConfig": "tsconfig.spec.json", 87 | "inlineStyleLanguage": "scss", 88 | "assets": [ 89 | "src/favicon.ico", 90 | "src/assets" 91 | ], 92 | "styles": [ 93 | "src/styles.scss" 94 | ], 95 | "scripts": [] 96 | } 97 | } 98 | } 99 | } 100 | }, 101 | "cli": { 102 | "analytics": false 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /TallerAngular/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pokedex-angular17", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "watch": "ng build --watch --configuration development", 9 | "test": "ng test" 10 | }, 11 | "private": true, 12 | "dependencies": { 13 | "@angular/animations": "^17.0.0", 14 | "@angular/common": "^17.0.0", 15 | "@angular/compiler": "^17.0.0", 16 | "@angular/core": "^17.0.0", 17 | "@angular/forms": "^17.0.0", 18 | "@angular/platform-browser": "^17.0.0", 19 | "@angular/platform-browser-dynamic": "^17.0.0", 20 | "@angular/router": "^17.0.0", 21 | "rxjs": "~7.8.0", 22 | "tslib": "^2.3.0", 23 | "zone.js": "~0.14.2" 24 | }, 25 | "devDependencies": { 26 | "@angular-devkit/build-angular": "^17.0.5", 27 | "@angular/cli": "^17.0.5", 28 | "@angular/compiler-cli": "^17.0.0", 29 | "@types/jasmine": "~5.1.0", 30 | "jasmine-core": "~5.1.0", 31 | "karma": "~6.4.0", 32 | "karma-chrome-launcher": "~3.2.0", 33 | "karma-coverage": "~2.2.0", 34 | "karma-jasmine": "~5.1.0", 35 | "karma-jasmine-html-reporter": "~2.1.0", 36 | "typescript": "~5.2.2" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /TallerAngular/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /TallerAngular/src/app/app.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerAngular/src/app/app.component.scss -------------------------------------------------------------------------------- /TallerAngular/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { RouterOutlet } from '@angular/router'; 4 | 5 | import { NavbarComponent } from './components/navbar/navbar.component'; 6 | 7 | @Component({ 8 | selector: 'app-root', 9 | standalone: true, 10 | imports: [CommonModule, RouterOutlet, NavbarComponent], 11 | templateUrl: './app.component.html', 12 | styleUrl: './app.component.scss' 13 | }) 14 | export class AppComponent { 15 | title = 'pokedex-angular17'; 16 | } 17 | -------------------------------------------------------------------------------- /TallerAngular/src/app/app.config.ts: -------------------------------------------------------------------------------- 1 | import { ApplicationConfig } from '@angular/core'; 2 | import { provideRouter } from '@angular/router'; 3 | 4 | import { routes } from './app.routes'; 5 | import { provideHttpClient } from '@angular/common/http'; 6 | 7 | export const appConfig: ApplicationConfig = { 8 | providers: [provideRouter(routes), provideHttpClient()], 9 | }; 10 | -------------------------------------------------------------------------------- /TallerAngular/src/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | import { HomeComponent } from './views/home/home.component'; 3 | 4 | export const routes: Routes = [ 5 | { 6 | path: '', 7 | component: HomeComponent, 8 | title: 'Home page', 9 | }, 10 | ]; 11 | -------------------------------------------------------------------------------- /TallerAngular/src/app/components/card-poke/card-poke.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
{{ data?.name }}
4 |
5 | @defer (on immediate) { 6 | 7 | } @placeholder { 8 | pokeball} 9 |
10 |
11 |

Basic information:

12 |
13 |
14 |

Number: {{ data?.id }}

15 |

Type: {{ data?.type }}

16 |

Weight: {{ data?.weight }} lb.

17 |

Height: {{ data?.height }} ft.

18 |
19 |
20 |
21 |

Abilities:

22 |
23 |
24 | 27 | 28 |
29 |
-------------------------------------------------------------------------------- /TallerAngular/src/app/components/card-poke/card-poke.component.scss: -------------------------------------------------------------------------------- 1 | .card-poke { 2 | width: 90%; 3 | max-width: 25rem; 4 | margin: 0 auto 5rem; 5 | box-shadow: 0 0 .9rem var(--color-secondary); 6 | border: 1.5px solid var(--color-primary); 7 | overflow: hidden; 8 | border-radius: .375rem; 9 | -webkit-border-radius: .375rem; 10 | -moz-border-radius: .375rem; 11 | -ms-border-radius: .375rem; 12 | -o-border-radius: .375rem; 13 | 14 | &__btn { 15 | background-color: var(--color-primary); 16 | border: none; 17 | color: white; 18 | cursor: pointer; 19 | transition: all .3s ease-in-out; 20 | text-transform: capitalize; 21 | 22 | &:hover { 23 | background-color: var(--color-secondary); 24 | } 25 | } 26 | 27 | &__img { 28 | padding: 3rem; 29 | } 30 | 31 | &__text { 32 | text-transform: capitalize; 33 | } 34 | 35 | &__title { 36 | text-transform: capitalize; 37 | text-align: center; 38 | font-size: 2rem; 39 | } 40 | 41 | &__subtitle { 42 | text-transform: capitalize; 43 | } 44 | } -------------------------------------------------------------------------------- /TallerAngular/src/app/components/card-poke/card-poke.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | import { Pokemon } from '../../models/pokedex.model'; 3 | import { ModalPokeComponent } from '../modal-poke/modal-poke.component'; 4 | 5 | @Component({ 6 | selector: 'app-card-poke', 7 | standalone: true, 8 | imports: [ModalPokeComponent], 9 | templateUrl: './card-poke.component.html', 10 | styleUrl: './card-poke.component.scss', 11 | }) 12 | export class CardPokeComponent { 13 | @Input() public data: null | Pokemon = null; 14 | } 15 | -------------------------------------------------------------------------------- /TallerAngular/src/app/components/fail-poke/fail-poke.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
{{ title }}
4 |
5 | fail-poke 7 |
-------------------------------------------------------------------------------- /TallerAngular/src/app/components/fail-poke/fail-poke.component.scss: -------------------------------------------------------------------------------- 1 | .card-poke-fail { 2 | width: 90%; 3 | max-width: 25rem; 4 | margin: 0 auto 5rem; 5 | box-shadow: 0 0 .9rem var(--color-secondary); 6 | border: 1.5px solid var(--color-primary); 7 | overflow: hidden; 8 | border-radius: .375rem; 9 | -webkit-border-radius: .375rem; 10 | -moz-border-radius: .375rem; 11 | -ms-border-radius: .375rem; 12 | -o-border-radius: .375rem; 13 | 14 | &__img { 15 | padding: 3rem; 16 | width: 350px; 17 | height: auto; 18 | margin: 0 auto; 19 | } 20 | 21 | &__title { 22 | text-align: center; 23 | font-size: 2rem; 24 | } 25 | } -------------------------------------------------------------------------------- /TallerAngular/src/app/components/fail-poke/fail-poke.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-fail-poke', 5 | standalone: true, 6 | imports: [], 7 | templateUrl: './fail-poke.component.html', 8 | styleUrl: './fail-poke.component.scss', 9 | }) 10 | export class FailPokeComponent { 11 | public title: string = 'No pokémon found.'; 12 | } 13 | -------------------------------------------------------------------------------- /TallerAngular/src/app/components/header/header.component.html: -------------------------------------------------------------------------------- 1 |
2 |

{{ title }}

3 |

{{ subtitle }}

4 |
-------------------------------------------------------------------------------- /TallerAngular/src/app/components/header/header.component.scss: -------------------------------------------------------------------------------- 1 | .header-poke { 2 | background-color: var(--color-secondary); 3 | color: white; 4 | padding: 2rem 0; 5 | text-align: center; 6 | 7 | &__title { 8 | font-size: 1.5rem; 9 | font-weight: 700; 10 | padding: 1rem 0; 11 | } 12 | 13 | &__subtitle { 14 | font-size: 1.25rem; 15 | } 16 | } -------------------------------------------------------------------------------- /TallerAngular/src/app/components/header/header.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-header', 5 | standalone: true, 6 | imports: [], 7 | templateUrl: './header.component.html', 8 | styleUrl: './header.component.scss' 9 | }) 10 | export class HeaderComponent { 11 | @Input() public title!: string; 12 | @Input() public subtitle!: string; 13 | } 14 | -------------------------------------------------------------------------------- /TallerAngular/src/app/components/loader/loader.component.html: -------------------------------------------------------------------------------- 1 |
2 | loading-poke 4 |
-------------------------------------------------------------------------------- /TallerAngular/src/app/components/loader/loader.component.scss: -------------------------------------------------------------------------------- 1 | .card-poke-loading { 2 | width: 100%; 3 | max-width: 25rem; 4 | margin: 0 auto; 5 | 6 | &__img { 7 | padding: 3rem; 8 | width: 350px; 9 | height: auto; 10 | margin: 0 auto; 11 | animation: .5s infinite linear rotation; 12 | -webkit-animation: .5s infinite linear rotation; 13 | } 14 | 15 | @keyframes rotation { 16 | from { 17 | transform: rotate(0deg); 18 | } 19 | 20 | to { 21 | transform: rotate(360deg); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /TallerAngular/src/app/components/loader/loader.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-loader', 5 | standalone: true, 6 | imports: [], 7 | templateUrl: './loader.component.html', 8 | styleUrl: './loader.component.scss' 9 | }) 10 | export class LoaderComponent { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /TallerAngular/src/app/components/modal-poke/modal-poke.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TallerAngular/src/app/components/modal-poke/modal-poke.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerAngular/src/app/components/modal-poke/modal-poke.component.scss -------------------------------------------------------------------------------- /TallerAngular/src/app/components/modal-poke/modal-poke.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | import { PokemonAbilities } from '../../models/pokedex.model'; 3 | 4 | @Component({ 5 | selector: 'app-modal-poke', 6 | standalone: true, 7 | imports: [], 8 | templateUrl: './modal-poke.component.html', 9 | styleUrl: './modal-poke.component.scss', 10 | }) 11 | export class ModalPokeComponent { 12 | @Input() public data: undefined | PokemonAbilities[] = []; 13 | } 14 | -------------------------------------------------------------------------------- /TallerAngular/src/app/components/navbar/navbar.component.html: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /TallerAngular/src/app/components/navbar/navbar.component.scss: -------------------------------------------------------------------------------- 1 | .navbar-poke { 2 | background-color: var(--color-primary); 3 | height: 60px; 4 | padding: 0; 5 | } 6 | -------------------------------------------------------------------------------- /TallerAngular/src/app/components/navbar/navbar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { RouterModule } from '@angular/router'; 3 | 4 | @Component({ 5 | selector: 'app-navbar', 6 | standalone: true, 7 | imports: [RouterModule], 8 | templateUrl: './navbar.component.html', 9 | styleUrl: './navbar.component.scss' 10 | }) 11 | export class NavbarComponent { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /TallerAngular/src/app/models/pokedex.model.ts: -------------------------------------------------------------------------------- 1 | export interface Pokemon { 2 | abilities: PokemonAbilities[]; 3 | name: string; 4 | id: number; 5 | image: string; 6 | type: string; 7 | weight: number; 8 | height: number; 9 | } 10 | 11 | export interface PokemonAbility { 12 | name: string; 13 | url: string; 14 | } 15 | 16 | export interface PokemonAbilities { 17 | ability: PokemonAbility; 18 | is_hidden: boolean; 19 | slot: number; 20 | } 21 | -------------------------------------------------------------------------------- /TallerAngular/src/app/views/home/home.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 |
6 |
7 | 8 |
9 |
10 | Pokémon 11 | 12 | 14 |
15 |
16 |
17 |
18 |
19 | @if (pokemon && !loading) { 20 | 21 | } @else if (loading) { 22 | 23 | } @else { 24 | } 25 |
26 |
27 |
-------------------------------------------------------------------------------- /TallerAngular/src/app/views/home/home.component.scss: -------------------------------------------------------------------------------- 1 | .label-container { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | justify-content: center; 6 | padding: 2rem 0 0; 7 | font-size: 1.25rem; 8 | 9 | strong { 10 | font-size: 1.35rem; 11 | color: var(--color-primary); 12 | } 13 | } 14 | 15 | .input-container { 16 | display: flex; 17 | align-items: center; 18 | justify-content: center; 19 | padding: 2rem 0; 20 | 21 | &__btn { 22 | background-color: var(--color-primary); 23 | border: none; 24 | color: white; 25 | cursor: pointer; 26 | transition: all .3s ease-in-out; 27 | text-transform: capitalize; 28 | 29 | &:hover { 30 | background-color: var(--color-secondary); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /TallerAngular/src/app/views/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { FormsModule } from '@angular/forms'; 3 | import { HeaderComponent } from '../../components/header/header.component'; 4 | import { CardPokeComponent } from '../../components/card-poke/card-poke.component'; 5 | import { FailPokeComponent } from '../../components/fail-poke/fail-poke.component'; 6 | import { HttpClient } from '@angular/common/http'; 7 | import { Pokemon } from '../../models/pokedex.model'; 8 | import { LoaderComponent } from '../../components/loader/loader.component'; 9 | 10 | @Component({ 11 | selector: 'app-home', 12 | standalone: true, 13 | imports: [ 14 | HeaderComponent, 15 | CardPokeComponent, 16 | FailPokeComponent, 17 | LoaderComponent, 18 | FormsModule, 19 | ], 20 | templateUrl: './home.component.html', 21 | styleUrl: './home.component.scss', 22 | }) 23 | export class HomeComponent { 24 | public title: string = 'Pokédex with Angular 17'; 25 | public subtitle: string = 'Based on PokeAPI'; 26 | public pokemonName: string = 'Mew'; 27 | public pokemon: null | Pokemon = null; 28 | public POKEAPI_URL_BASE: string = 'https://pokeapi.co/api/v2/pokemon/'; 29 | public loading: boolean = true; 30 | 31 | constructor(private http: HttpClient) {} 32 | 33 | ngOnInit(): void { 34 | this.searchPokemon(); 35 | } 36 | 37 | private pokeNameSanitize(pokeName: string): string { 38 | return pokeName.toLowerCase().trim(); 39 | } 40 | 41 | public searchPokemon(): void { 42 | const pokeName = this.pokeNameSanitize(this.pokemonName); 43 | this.loading = true; 44 | 45 | this.http.get(this.POKEAPI_URL_BASE + pokeName).subscribe( 46 | (data: any) => { 47 | this.pokemon = { 48 | abilities: data.abilities, 49 | height: data.height, 50 | id: data.id, 51 | image: data.sprites?.other?.dream_world?.front_default, 52 | name: data.name, 53 | type: data.types[0].type.name, 54 | weight: data.weight, 55 | }; 56 | this.loading = false; 57 | }, 58 | (error: any) => { 59 | console.log(error); 60 | this.pokemon = null; 61 | this.loading = false; 62 | } 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /TallerAngular/src/assets/images/poke-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerAngular/src/assets/images/poke-logo.png -------------------------------------------------------------------------------- /TallerAngular/src/assets/images/pokeball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerAngular/src/assets/images/pokeball.png -------------------------------------------------------------------------------- /TallerAngular/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerAngular/src/favicon.ico -------------------------------------------------------------------------------- /TallerAngular/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Pokédex Angular 17 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /TallerAngular/src/main.ts: -------------------------------------------------------------------------------- 1 | import { bootstrapApplication } from '@angular/platform-browser'; 2 | import { appConfig } from './app/app.config'; 3 | import { AppComponent } from './app/app.component'; 4 | 5 | bootstrapApplication(AppComponent, appConfig) 6 | .catch((err) => console.error(err)); 7 | -------------------------------------------------------------------------------- /TallerAngular/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | :root { 3 | --color-primary: #ef5350; 4 | --color-secondary: #263238; 5 | } 6 | 7 | body, 8 | html, 9 | p, 10 | h1, 11 | h2, 12 | h3, 13 | h4, 14 | h5, 15 | h6, 16 | a, 17 | ul, 18 | li, 19 | button, 20 | input, 21 | select, 22 | option, 23 | textarea, 24 | form, 25 | label, 26 | img, 27 | div, 28 | span, 29 | section, 30 | header, 31 | footer, 32 | nav, 33 | main, 34 | article, 35 | aside, 36 | figure, 37 | figcaption, 38 | table, 39 | tbody, 40 | thead, 41 | tr, 42 | td { 43 | margin: 0; 44 | padding: 0; 45 | } 46 | -------------------------------------------------------------------------------- /TallerAngular/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /TallerAngular/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "outDir": "./dist/out-tsc", 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "esModuleInterop": true, 13 | "sourceMap": true, 14 | "declaration": false, 15 | "experimentalDecorators": true, 16 | "moduleResolution": "node", 17 | "importHelpers": true, 18 | "target": "ES2022", 19 | "module": "ES2022", 20 | "useDefineForClassFields": false, 21 | "lib": [ 22 | "ES2022", 23 | "dom" 24 | ] 25 | }, 26 | "angularCompilerOptions": { 27 | "enableI18nLegacyMessageIdFormat": false, 28 | "strictInjectionParameters": true, 29 | "strictInputAccessModifiers": true, 30 | "strictTemplates": true 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /TallerAngular/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "include": [ 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /TallerGraphql/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # yarn v2 126 | .yarn/cache 127 | .yarn/unplugged 128 | .yarn/build-state.yml 129 | .yarn/install-state.gz 130 | .pnp.* -------------------------------------------------------------------------------- /TallerGraphql/MaterialDeApoyo.md: -------------------------------------------------------------------------------- 1 | # Material de Apoyo para el Taller de GraphQL Yoga y TypeScript 2 | 3 | Bienvenido al taller de desarrollo backend utilizando GraphQL Yoga y TypeScript. Aquí encontrarás una lista de recursos y enlaces que te serán de gran utilidad a lo largo de este curso. Estos materiales te proporcionarán una base sólida para comprender y trabajar con estas tecnologías. 4 | 5 | ## Contenidos 6 | 7 | 1. **Introducción a GraphQL Yoga** 8 | 2. **Fundamentos de TypeScript** 9 | 3. **Configuración de Node.js y npm** 10 | 4. **Uso de Git para el control de versiones** 11 | 12 | --- 13 | 14 | ### 1. Introducción a GraphQL Yoga 15 | 16 | GraphQL Yoga es una implementación de servidor GraphQL fácil de usar y completamente equipada. Proporciona una manera eficiente y flexible de construir APIs de GraphQL. 17 | 18 | - [GraphQL Yoga Official Documentation](https://the-guild.dev/graphql/yoga-server) 19 | 20 | --- 21 | 22 | ### 2. Fundamentos de TypeScript 23 | 24 | TypeScript es un lenguaje de programación desarrollado por Microsoft que se basa en JavaScript añadiendo tipado estático. Es especialmente útil para desarrollar aplicaciones grandes. 25 | 26 | - [TypeScript Official Documentation](https://www.typescriptlang.org/) 27 | 28 | --- 29 | 30 | ### 3. Configuración de Node.js y npm 31 | 32 | Node.js es un entorno de ejecución para JavaScript en el servidor. npm es el sistema de gestión de paquetes que acompaña a Node.js, permitiéndote instalar y manejar librerías fácilmente. 33 | 34 | - [Node.js Official Website](https://nodejs.org/en) 35 | - [npm Official Documentation](https://docs.npmjs.com/) 36 | 37 | --- 38 | 39 | ### 4. Uso de Git para el control de versiones 40 | 41 | Git es un sistema de control de versiones distribuido gratuito y de código abierto, diseñado para manejar todo, desde proyectos pequeños a muy grandes, con velocidad y eficiencia. 42 | 43 | - [Git Official Website](https://git-scm.com/) 44 | 45 | --- 46 | 47 | Estos recursos son esenciales para el taller. Te recomendamos revisar cada uno de ellos antes de comenzar con las sesiones prácticas. Estar familiarizado con estos materiales te ayudará a aprovechar al máximo el taller. 48 | 49 | ¡Esperamos que encuentres estos recursos útiles y que disfrutes aprendiendo y desarrollando con GraphQL Yoga y TypeScript! 50 | -------------------------------------------------------------------------------- /TallerGraphql/Presentacion.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerGraphql/Presentacion.pdf -------------------------------------------------------------------------------- /TallerGraphql/README.md: -------------------------------------------------------------------------------- 1 | # Taller: Desarrollando una Pokedex con GaphQL 2 | 3 | **Mentor de esta edición:** Benjamin Perez 4 | 5 | ## Descripción del Taller 6 | Este taller te introduce en el mundo del desarrollo backend con GraphQL Yoga y TypeScript. Te enfocarás en construir un **CRUD (Create, Read, Update, Delete)** - un componente esencial en la mayoría de las aplicaciones web. Utilizarás GraphQL Yoga, una implementación completamente equipada de un servidor GraphQL, combinada con la potencia y seguridad de TypeScript. 7 | 8 | ## Objetivo del Taller 9 | El objetivo es brindarte las habilidades necesarias para construir una aplicación backend robusta y escalable. Aprenderás los fundamentos de GraphQL Yoga, cómo integrarlo con TypeScript y cómo implementar operaciones CRUD en tu aplicación. Al final del taller, tendrás un proyecto de backend funcional que podrás expandir y modificar. 10 | 11 | ## Prerrequisitos 12 | - Conocimientos en TypeScript / JavaScript Sirve. 13 | - Cuenta activa en GitHub. 14 | - Tener instalado Node.js y npm en tu laptop. 15 | - Laptop con un editor de codigo. 16 | 17 | ## Material de apoyo 18 | Dentro de esta carpeta encontrarás archivos, guías y recursos que te serán de gran utilidad durante el taller. Te recomendamos descargar y revisar estos materiales con anticipación para aprovechar al máximo la sesión. 19 | 20 | --- 21 | 22 | Al finalizar este taller, no solo habrás creado un CRUD con GraphQL Yoga y TypeScript, sino que también tendrás una base sólida para explorar proyectos más avanzados y desafiantes en el mundo del desarrollo backend. 23 | 24 | ¡Te esperamos para aprender, codificar y disfrutar la experiencia de crear con GraphQL Yoga y TypeScript! 25 | -------------------------------------------------------------------------------- /TallerGraphql/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graphqlyoga", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "main.ts", 6 | "scripts": { 7 | "dev": "cross-env NODE_ENV=development ts-node-dev --exit-child --respawn src/main.ts", 8 | "start": "ts-node src/main.ts" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "@types/node": "20.10.4", 15 | "cross-env": "7.0.3", 16 | "ts-node": "10.9.2", 17 | "ts-node-dev": "2.0.0", 18 | "typescript": "5.3.3" 19 | }, 20 | "dependencies": { 21 | "@graphql-tools/schema": "^10.0.2", 22 | "@pothos/core": "^3.40.0", 23 | "graphql": "^16.8.1", 24 | "graphql-yoga": "^5.0.2" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /TallerGraphql/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createYoga } from "graphql-yoga"; 2 | import { createServer } from "node:http"; 3 | import { schema } from "./schema"; 4 | 5 | export const yoga = createYoga({ 6 | graphiql: (_) => { 7 | return { 8 | title: "TechSchool V2 - GraphQL Pokédex", 9 | }; 10 | }, 11 | schema, 12 | logging: "debug", 13 | }); 14 | 15 | const server = createServer(yoga); 16 | 17 | server.listen(3000, () => { 18 | console.log("Visit http://localhost:3000/graphql"); 19 | }); 20 | -------------------------------------------------------------------------------- /TallerGraphql/src/schema/index.ts: -------------------------------------------------------------------------------- 1 | import SchemaBuilder from "@pothos/core"; 2 | 3 | export const builder = new SchemaBuilder({}); 4 | 5 | export const schema = builder.toSchema(); 6 | -------------------------------------------------------------------------------- /TallerGraphql/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "commonjs" /* Specify what module code is generated. */, 29 | // "rootDir": "./", /* Specify the root folder within your source files. */ 30 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 38 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 39 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 40 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 41 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 42 | // "resolveJsonModule": true, /* Enable importing .json files. */ 43 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 44 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 45 | 46 | /* JavaScript Support */ 47 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 48 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 49 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 50 | 51 | /* Emit */ 52 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 53 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 54 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 55 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 56 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 57 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 58 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 59 | // "removeComments": true, /* Disable emitting comments. */ 60 | // "noEmit": true, /* Disable emitting files from a compilation. */ 61 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 62 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 63 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 64 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 65 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 66 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 67 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 68 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 69 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 70 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 71 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 72 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 73 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 74 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 75 | 76 | /* Interop Constraints */ 77 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 78 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ 79 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 80 | "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, 81 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 82 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, 83 | 84 | /* Type Checking */ 85 | "strict": true /* Enable all strict type-checking options. */, 86 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 87 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 88 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 89 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 90 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 91 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 92 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 93 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 94 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 95 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 96 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 97 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 98 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 99 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 100 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 101 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 102 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 103 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 104 | 105 | /* Completeness */ 106 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 107 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /TallerNode/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /TallerNode/README.md: -------------------------------------------------------------------------------- 1 | # Taller: 2 | 3 | **Mentor de esta edición:** David Quezada (@DvdQzd) 4 | 5 | ## Descripción del Taller 6 | En este taller, exploraremos la construcción de un servidor de intercambio Pokémon utilizando Node.js. Aprenderemos a manejar solicitudes de intercambio y consultas de Pokémon disponibles, simulando un centro de intercambio Pokémon virtual. 7 | 8 | ## Objetivo del Taller 9 | El objetivo principal es que los participantes adquieran experiencia práctica en el desarrollo de servidores con Node.js y el manejo de solicitudes HTTP. Al finalizar el taller, los participantes deberían tener un simulador funcional de centro de intercambio Pokémon y comprender los conceptos básicos de la construcción de servidores web con Node.js. 10 | 11 | ## Prerrequisitos 12 | - Laptop con acceso a un editor de texto. 13 | - Conocimientos básicos de JavaScript y Node.js. 14 | - Tener instalado Node.js y npm en tu laptop. 15 | - Cuenta activa en GitHub. 16 | 17 | ## Material de apoyo 18 | - Documentación oficial de Node.js: https://nodejs.org/en/docs/ 19 | - Documentación oficial de npm: https://docs.npmjs.com/ 20 | - Documentación oficial de Express: https://expressjs.com/ 21 | - Documentación oficial de MongoDB: https://docs.mongodb.com/ 22 | 23 | ## ¡Diviértete intercambiando Pokémon! 24 | 25 | Gracias por participar en este taller. Espero que hayas disfrutado construyendo tu propio simulador de centro de intercambio Pokémon con Node.js. 26 | 27 | ¡Buena suerte en tus futuros proyectos y que tus Pokémon evolucionen fuertes y saludables! 28 | -------------------------------------------------------------------------------- /TallerNode/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const mongoose = require('mongoose'); 3 | const { PokemonServiceFactory } = require('./services/pokemon.service.factory.js'); 4 | 5 | const app = express(); 6 | app.use(express.json()); 7 | 8 | const mongoDB = true; // cambiar a false para usar el servicio de pokemon.service.js 9 | 10 | const pokemonService = new PokemonServiceFactory().getPokemonService(mongoDB); 11 | 12 | mongoose.connect('mongodb://localhost/pokemon-db', { 13 | useNewUrlParser: true, 14 | useUnifiedTopology: true, 15 | }) 16 | 17 | app.post('/pokemon', (req, res) => { 18 | const data = req.body; 19 | const received = pokemonService.savePokemon(data); 20 | if (received) { 21 | res.send(received) 22 | } else { 23 | res.status(404).send({ message: 'No hay pokemon disponible' }) 24 | } 25 | }); 26 | 27 | app.get('/pokemon/trainer/:id', (req, res) => { 28 | const id = req.params.id; 29 | // buscar lista de pkmn por trainerId y retornar pkmn intercambiados 30 | }); 31 | 32 | app.get('/pokemon', (req, res) => { 33 | res.send(pokemonService.getSavedPokemon()) 34 | }); 35 | 36 | app.put('/pokemon', (req, res) => { 37 | // editar el pkmn 38 | }) 39 | 40 | app.listen(8080, () => { 41 | console.log('servidor funcionando') 42 | }) -------------------------------------------------------------------------------- /TallerNode/models/pokemon.model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const pokemonSchema = new mongoose.Schema({ 4 | trainerId: { 5 | type: Number, 6 | required: true 7 | }, 8 | transferId: { 9 | type: Number, 10 | required: true 11 | }, 12 | availableForTrade: { 13 | type: Boolean, 14 | default: true 15 | }, 16 | pokemonData: { 17 | id: { 18 | type: Number, 19 | required: true 20 | }, 21 | name: { 22 | type: String, 23 | required: true 24 | } 25 | }, 26 | level: { 27 | type: Number, 28 | required: true 29 | } 30 | }); 31 | 32 | const Pokemon = mongoose.model('Pokemon', pokemonSchema); 33 | 34 | module.exports = Pokemon; 35 | -------------------------------------------------------------------------------- /TallerNode/normal_IMG_2503.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerNode/normal_IMG_2503.webp -------------------------------------------------------------------------------- /TallerNode/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tallernode", 3 | "version": "1.0.0", 4 | "description": "**Mentor de esta edición:** David Quezada (@DvdQzd)", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "express": "^4.21.2", 14 | "mongoose": "^8.9.5" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /TallerNode/services/pokemon.service.factory.js: -------------------------------------------------------------------------------- 1 | const { PokemonService } = require('./pokemonMongo.service'); 2 | const { PokemonMongoService } = require('./pokemonMongo.service'); 3 | 4 | class PokemonServiceFactory { 5 | async getPokemonService(mongoDB) { 6 | if(mongoDB) return new PokemonMongoService(); 7 | return new PokemonService(); 8 | } 9 | } 10 | 11 | module.exports = { 12 | PokemonServiceFactory 13 | } -------------------------------------------------------------------------------- /TallerNode/services/pokemon.service.js: -------------------------------------------------------------------------------- 1 | const savedPokemon = [ 2 | { 3 | id: 1, 4 | name: 'Pikachu', 5 | type: 'Electric', 6 | availableForTrade: true, 7 | trainerId: 1 8 | }, 9 | ]; 10 | 11 | class PokemonService { 12 | savePokemon(data){ 13 | const received = this.getRandomPokemon(data.trainerId); 14 | if(received){ 15 | received.availableForTrade = false; 16 | savedPokemon.splice(savedPokemon.indexOf(received), 1); 17 | savedPokemon.push(received); 18 | data.availableForTrade = false; 19 | savedPokemon.push(data) 20 | return received; 21 | } 22 | } 23 | 24 | getSavedPokemon(){ 25 | return savedPokemon; 26 | } 27 | 28 | getRandomPokemon(trainerId){ 29 | return savedPokemon.find( 30 | pokemon => (pokemon.availableForTrade === true) && 31 | (pokemon.trainerId !== trainerId) 32 | ); 33 | } 34 | } 35 | 36 | module.exports = { 37 | PokemonService 38 | } -------------------------------------------------------------------------------- /TallerNode/services/pokemonMongo.service.js: -------------------------------------------------------------------------------- 1 | const PokemonModel = require('./pokemon.model'); 2 | 3 | class PokemonMongoService { 4 | async savePokemon(data) { 5 | const received = await this.getRandomPokemon(data.trainerId); 6 | if (received) { 7 | received.availableForTrade = false; 8 | await PokemonModel.updateOne({ _id: received._id }, received); 9 | data.availableForTrade = false; 10 | await PokemonModel.create(data); 11 | return received; 12 | } 13 | } 14 | 15 | async getSavedPokemon() { 16 | return await PokemonModel.find(); 17 | } 18 | 19 | async getRandomPokemon(trainerId) { 20 | return await PokemonModel.findOne({ 21 | availableForTrade: true, 22 | trainerId: { $ne: trainerId }, 23 | }); 24 | } 25 | } 26 | 27 | module.exports = { 28 | PokemonMongoService, 29 | }; 30 | -------------------------------------------------------------------------------- /TallerRankingNode/backend/.env.example: -------------------------------------------------------------------------------- 1 | PORT=3000 2 | PERSISTENCE=mongo 3 | MONGO_URL=mongodb+srv://tsvalpo2024:tsvalpo@cluster0.giykqux.mongodb.net/ranking -------------------------------------------------------------------------------- /TallerRankingNode/backend/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | .env 4 | -------------------------------------------------------------------------------- /TallerRankingNode/backend/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.0' 2 | 3 | services: 4 | mongo_db: 5 | image: mongo 6 | container_name: mongo_db_ranking 7 | ports: 8 | - 27017:27017 9 | volumes: 10 | - mongoranking:/data/configdb 11 | - mongoranking:/data/db 12 | 13 | volumes: 14 | mongoranking: {} 15 | -------------------------------------------------------------------------------- /TallerRankingNode/backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "taller-ranking", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "start": "node src/server.js", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "cors": "^2.8.5", 16 | "express": "^4.21.2", 17 | "jsonwebtoken": "^9.0.2", 18 | "mongoose": "^8.9.5" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /TallerRankingNode/backend/src/config/constants.js: -------------------------------------------------------------------------------- 1 | if(process.env.NODE_ENV !== 'production'){ 2 | process.loadEnvFile(); 3 | } 4 | 5 | export const PORT = process.env.PORT || 3000; 6 | export const PERSISTENCE = process.env.PERSISTENCE || 'memory'; 7 | export const MONGO_URL = process.env.MONGO_URL || 'mongodb://localhost:27017/ranking'; -------------------------------------------------------------------------------- /TallerRankingNode/backend/src/controllers/ranking.controller.js: -------------------------------------------------------------------------------- 1 | import RankingService from '../services/ranking.service.js'; 2 | import RankingDaoFactory from '../db/dao/ranking.dao.factory.js'; 3 | import RankingRepository from '../db/ranking.repository.js'; 4 | 5 | const rankingRepository = new RankingRepository(RankingDaoFactory.getDao()); 6 | const rankingService = new RankingService(rankingRepository); 7 | 8 | export const addRecord = async (req, res) => { 9 | const { body } = req; 10 | try { 11 | // Add a record to the ranking 12 | } catch (error) { 13 | res.status(400).send({ message: error.message }); 14 | } 15 | }; 16 | 17 | export const getRanking = async (req, res) => { 18 | try { 19 | // Get the ranking 20 | } catch { 21 | res.status(400).send({ message: error.message }); 22 | } 23 | 24 | } 25 | 26 | export const reset = async (req, res) => { 27 | try { 28 | // Reset the ranking 29 | } catch (error) { 30 | res.status(400).send({ message: error.message }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /TallerRankingNode/backend/src/db/dao/memory/ranking.dao.js: -------------------------------------------------------------------------------- 1 | export default class RankingMemoryDao { 2 | constructor() { 3 | this.ranking = []; 4 | } 5 | 6 | async addRecord(record) { 7 | this.ranking.push(record); 8 | } 9 | 10 | async updateRecord(record) { 11 | const index = this.ranking.findIndex((r) => r.player === record.player); 12 | if (index === -1) return; 13 | this.ranking[index] = record; 14 | } 15 | 16 | async getRanking() { 17 | return this.ranking.sort((a, b) => b.score - a.score); 18 | } 19 | 20 | async reset() { 21 | this.ranking = []; 22 | } 23 | 24 | async getRecordByPlayer(player) { 25 | const index = this.ranking.findIndex((r) => r.player === player); 26 | if (index === -1) return null; 27 | return this.ranking[index]; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /TallerRankingNode/backend/src/db/dao/mongo/connection.js: -------------------------------------------------------------------------------- 1 | import mongoose from 'mongoose'; 2 | import { MONGO_URL } from '../../../config/constants.js'; 3 | 4 | mongoose.connect(MONGO_URL).then(() => { 5 | console.log('MongoDB connected'); 6 | }).catch((error) => { 7 | console.log('MongoDB connection error', error); 8 | }); 9 | -------------------------------------------------------------------------------- /TallerRankingNode/backend/src/db/dao/mongo/models/record.js: -------------------------------------------------------------------------------- 1 | import mongoose from "mongoose"; 2 | 3 | const recordSchema = new mongoose.Schema({ 4 | player: { 5 | type: String, 6 | required: true 7 | }, 8 | score: { 9 | type: Number, 10 | required: true 11 | }, 12 | date: { 13 | type: Date, 14 | default: Date.now 15 | } 16 | }); 17 | 18 | const Record = mongoose.model("Record", recordSchema); 19 | 20 | export default Record; 21 | -------------------------------------------------------------------------------- /TallerRankingNode/backend/src/db/dao/mongo/ranking.dao.js: -------------------------------------------------------------------------------- 1 | import Record from "./models/record.js"; 2 | 3 | export default class RankingMongoDao { 4 | constructor() {} 5 | 6 | async addRecord(record) { 7 | try { 8 | // Create a new record 9 | } catch (error) { 10 | console.error("Error adding record: ", error); 11 | throw error; 12 | } 13 | } 14 | 15 | async updateRecord(record) { 16 | try { 17 | // Update the record 18 | } catch (error) { 19 | console.error("Error updating record: ", error); 20 | throw error; 21 | } 22 | } 23 | 24 | async getRanking() { 25 | try { 26 | // Get the ranking 27 | } catch (error) { 28 | console.error("Error getting ranking: ", error); 29 | return []; 30 | } 31 | } 32 | 33 | async reset() { 34 | try { 35 | // Reset the ranking 36 | } catch (error) { 37 | console.error("Error resetting ranking: ", error); 38 | throw error; 39 | } 40 | } 41 | 42 | async getRecordByPlayer(player) { 43 | try{ 44 | // Get the record by player 45 | } catch (error) { 46 | console.error("Error getting record by player: ", error); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /TallerRankingNode/backend/src/db/dao/ranking.dao.factory.js: -------------------------------------------------------------------------------- 1 | import { PERSISTENCE } from "../../config/constants.js"; 2 | import RankingMemoryDao from "./memory/ranking.dao.js"; 3 | import RankingMongoDao from "./mongo/ranking.dao.js"; 4 | 5 | export default class RankingDaoFactory { 6 | constructor() {} 7 | 8 | static getDao() { 9 | switch (PERSISTENCE) { 10 | case "memory": 11 | return new RankingMemoryDao(); 12 | case "mongo": 13 | return new RankingMongoDao(); 14 | default: 15 | return new RankingMemoryDao(); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /TallerRankingNode/backend/src/db/dto/record.dto.js: -------------------------------------------------------------------------------- 1 | export default class RecordDTO { 2 | constructor({ player, score }) { 3 | this.player = player; 4 | this.score = score; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /TallerRankingNode/backend/src/db/ranking.repository.js: -------------------------------------------------------------------------------- 1 | import RecordDTO from './dto/record.dto.js'; 2 | 3 | export default class RankingRepository { 4 | 5 | constructor(dao) { 6 | this.dao = dao; 7 | } 8 | 9 | async addRecord(record) { 10 | return this.dao.addRecord(new RecordDTO(record)); 11 | } 12 | 13 | async updateRecord(record) { 14 | return this.dao.updateRecord(new RecordDTO(record)); 15 | } 16 | 17 | async getRanking() { 18 | return this.dao.getRanking(); 19 | } 20 | 21 | async reset() { 22 | return this.dao.reset(); 23 | } 24 | 25 | async getRecordByPlayer(player) { 26 | return this.dao.getRecordByPlayer(player); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /TallerRankingNode/backend/src/middlewares/auth.middleware.js: -------------------------------------------------------------------------------- 1 | import jwt from 'jsonwebtoken'; 2 | 3 | const PRIVATE_KEY = "TechschoolValpo2024"; 4 | 5 | export const generateToken = (user) => { 6 | const token = jwt.sign({ user }, PRIVATE_KEY, { expiresIn: '1d' }); 7 | return token; 8 | } 9 | 10 | export const authToken = (req, res, next) => { 11 | const authHeader = req.headers.authorization; 12 | if (!authHeader) return res.status(401).send({ status: "error", error: "Unauthorized" }) 13 | console.log(authHeader); 14 | const token = authHeader.split(' ')[1]; 15 | jwt.verify(token, PRIVATE_KEY, (error, credentials) => { 16 | console.log(error); 17 | if (error) return res.status(401).send({ status: "error", error: "Unauthorized" }) 18 | req.user = credentials.user; 19 | next(); 20 | }) 21 | } 22 | 23 | export const login = (req, res, next) => { 24 | const { user, password } = req.body; 25 | 26 | if (user !== "JavascriptChile" || password !== "1234") { 27 | return res.status(401).send({ status: "error", error: "Unauthorized" }); 28 | } 29 | 30 | req.user = user; 31 | next(); 32 | }; 33 | -------------------------------------------------------------------------------- /TallerRankingNode/backend/src/routers/ranking.router.js: -------------------------------------------------------------------------------- 1 | // create a new ranking router -------------------------------------------------------------------------------- /TallerRankingNode/backend/src/server.js: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import cors from "cors"; 3 | import { PORT, PERSISTENCE } from "./config/constants.js"; 4 | import rankingRouter from "./routers/ranking.router.js"; 5 | 6 | const app = express(); 7 | 8 | app.use(cors()); 9 | app.use(express.json()); 10 | 11 | app.use("/api/ranking", rankingRouter); 12 | 13 | app.listen(PORT, () => { 14 | console.log(`Ranking server is running on port ${PORT}`); 15 | }); 16 | 17 | if(PERSISTENCE === "mongo") { 18 | import("./db/dao/mongo/connection.js"); 19 | } else { 20 | console.log("Using memory database"); 21 | } 22 | -------------------------------------------------------------------------------- /TallerRankingNode/backend/src/services/ranking.service.js: -------------------------------------------------------------------------------- 1 | export default class RankingService { 2 | constructor(rankingRepository) { 3 | this.rankingRepository = rankingRepository; 4 | } 5 | 6 | async addRecord(record) { 7 | const existingRecord = await this.rankingRepository.getRecordByPlayer(record.player); 8 | 9 | if (!existingRecord) { 10 | return await this.rankingRepository.addRecord(record); 11 | } else if (record.score > existingRecord.score) { 12 | return await this.rankingRepository.updateRecord(record); 13 | } else { 14 | throw new Error("Record score is same as or lower than existing record"); 15 | } 16 | } 17 | 18 | async getRanking() { 19 | const ranking = await this.rankingRepository.getRanking(); 20 | console.log({ ranking }) 21 | return ranking; 22 | } 23 | 24 | async reset() { 25 | await this.rankingRepository.reset(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /TallerRankingNode/frontend/.env.local.example: -------------------------------------------------------------------------------- 1 | RANKING_SERVICE_URL=http://localhost:3001/api/ranking -------------------------------------------------------------------------------- /TallerRankingNode/frontend/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /TallerRankingNode/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /TallerRankingNode/frontend/GUID.txt: -------------------------------------------------------------------------------- 1 | 8d7f1f9d7562d5941a6c0cef8c5dca07 -------------------------------------------------------------------------------- /TallerRankingNode/frontend/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 2021.3.13f1 2 | m_EditorVersionWithRevision: 2021.3.13f1 (9e7d58001ecf) 3 | -------------------------------------------------------------------------------- /TallerRankingNode/frontend/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /TallerRankingNode/frontend/app/Score.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import React, { useState } from 'react'; 4 | 5 | const ScoreRectangle = ({playerName} : {playerName: string}) => { 6 | const [itemsPickedUp, setItemsPickedUp] = useState(0); 7 | 8 | window.addEventListener('ItemPickedUp', () => { 9 | setItemsPickedUp(itemsPickedUp + 1); 10 | }); 11 | 12 | return ( 13 |
21 |
36 | {itemsPickedUp} 37 |
38 | 39 | {/*
*/} 40 |
41 | 57 |
58 | 59 | 60 | ); 61 | }; 62 | 63 | export default ScoreRectangle; -------------------------------------------------------------------------------- /TallerRankingNode/frontend/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerRankingNode/frontend/app/favicon.ico -------------------------------------------------------------------------------- /TallerRankingNode/frontend/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | :root { 7 | --background: 0 0% 100%; 8 | --foreground: 222.2 84% 4.9%; 9 | 10 | --card: 0 0% 100%; 11 | --card-foreground: 222.2 84% 4.9%; 12 | 13 | --popover: 0 0% 100%; 14 | --popover-foreground: 222.2 84% 4.9%; 15 | 16 | --primary: 222.2 47.4% 11.2%; 17 | --primary-foreground: 210 40% 98%; 18 | 19 | --secondary: 210 40% 96.1%; 20 | --secondary-foreground: 222.2 47.4% 11.2%; 21 | 22 | --muted: 210 40% 96.1%; 23 | --muted-foreground: 215.4 16.3% 46.9%; 24 | 25 | --accent: 210 40% 96.1%; 26 | --accent-foreground: 222.2 47.4% 11.2%; 27 | 28 | --destructive: 0 84.2% 60.2%; 29 | --destructive-foreground: 210 40% 98%; 30 | 31 | --border: 214.3 31.8% 91.4%; 32 | --input: 214.3 31.8% 91.4%; 33 | --ring: 222.2 84% 4.9%; 34 | 35 | --radius: 0.5rem; 36 | } 37 | 38 | .dark { 39 | --background: 222.2 84% 4.9%; 40 | --foreground: 210 40% 98%; 41 | 42 | --card: 222.2 84% 4.9%; 43 | --card-foreground: 210 40% 98%; 44 | 45 | --popover: 222.2 84% 4.9%; 46 | --popover-foreground: 210 40% 98%; 47 | 48 | --primary: 210 40% 98%; 49 | --primary-foreground: 222.2 47.4% 11.2%; 50 | 51 | --secondary: 217.2 32.6% 17.5%; 52 | --secondary-foreground: 210 40% 98%; 53 | 54 | --muted: 217.2 32.6% 17.5%; 55 | --muted-foreground: 215 20.2% 65.1%; 56 | 57 | --accent: 217.2 32.6% 17.5%; 58 | --accent-foreground: 210 40% 98%; 59 | 60 | --destructive: 0 62.8% 30.6%; 61 | --destructive-foreground: 210 40% 98%; 62 | 63 | --border: 217.2 32.6% 17.5%; 64 | --input: 217.2 32.6% 17.5%; 65 | --ring: 212.7 26.8% 83.9%; 66 | } 67 | } 68 | 69 | @layer base { 70 | * { 71 | @apply border-border; 72 | } 73 | body { 74 | @apply bg-background text-foreground; 75 | } 76 | } -------------------------------------------------------------------------------- /TallerRankingNode/frontend/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import { Inter } from "next/font/google"; 3 | import "./globals.css"; 4 | 5 | const inter = Inter({ subsets: ["latin"] }); 6 | 7 | export const metadata: Metadata = { 8 | title: "Create Next App", 9 | description: "Generated by create next app", 10 | }; 11 | 12 | export default function RootLayout({ 13 | children, 14 | }: Readonly<{ 15 | children: React.ReactNode; 16 | }>) { 17 | return ( 18 | 19 | 20 | 21 | 22 | {children} 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /TallerRankingNode/frontend/app/page.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useEffect, useState } from 'react' 4 | import ScoreRectangle from './Score'; 5 | 6 | import { 7 | AlertDialog, 8 | AlertDialogAction, 9 | AlertDialogCancel, 10 | AlertDialogContent, 11 | AlertDialogDescription, 12 | AlertDialogFooter, 13 | AlertDialogHeader, 14 | AlertDialogTitle, 15 | AlertDialogTrigger, 16 | } from "@/components/ui/alert-dialog" 17 | 18 | 19 | declare var createUnityInstance: any; 20 | declare var SendMessage: any; 21 | declare var FocusCanvas: any; 22 | 23 | export default function Home() { 24 | 25 | const [playerName, setPlayer] = useState(''); 26 | const [showGame, setShowGame] = useState(false); 27 | 28 | var gameReady = false; 29 | 30 | // Called by Unity in GameControl's start function 31 | 32 | 33 | function FocusCanvas(focus: any) { 34 | if (gameReady) { 35 | SendMessage("GameControl", "FocusCanvas", focus); 36 | } 37 | } 38 | 39 | window.addEventListener('click', function (e) { 40 | if (e.target && (e.target as HTMLElement).id == "canvas") { 41 | // Clicked on canvas 42 | FocusCanvas("1"); 43 | } else { 44 | // Clicked outside of canvas 45 | FocusCanvas("0"); 46 | } 47 | }); 48 | 49 | useEffect(() => { 50 | 51 | if(showGame){ 52 | 53 | // function GameControlReady() { 54 | // gameReady = true; 55 | // } 56 | 57 | /*** 58 | * WebGL Game 59 | */ 60 | var container = document.querySelector("#unity-container"); 61 | var canvas = document.querySelector("#unity-canvas"); 62 | var loadingBar = document.querySelector("#unity-loading-bar"); 63 | var progressBarFull = document.querySelector("#unity-progress-bar-full"); 64 | var fullscreenButton = document.querySelector("#unity-fullscreen-button"); 65 | var warningBanner = document.querySelector("#unity-warning"); 66 | 67 | // Shows a temporary message banner/ribbon for a few seconds, or 68 | // a permanent error message on top of the canvas if type=='error'. 69 | // If type=='warning', a yellow highlight color is used. 70 | // Modify or remove this function to customize the visually presented 71 | // way that non-critical warnings and error messages are presented to the 72 | // user. 73 | // function unityShowBanner(_msg: string, type: string | undefined) { 74 | // function updateBannerVisibility() { 75 | // if (warningBanner) { 76 | // (warningBanner as HTMLElement).style.display = warningBanner.children.length ? 'block' : 'none'; 77 | // } 78 | // } 79 | // var div = document.createElement('div'); 80 | // if (warningBanner) { 81 | // warningBanner.appendChild(div); 82 | // if (type == 'error') div.setAttribute('style', 'background: red; padding: 10px;'); 83 | // else { 84 | // if (type == 'warning') div.setAttribute('style', 'background: yellow; padding: 10px;'); 85 | // setTimeout(function () { 86 | // if (warningBanner) { 87 | // warningBanner.removeChild(div); 88 | // updateBannerVisibility(); 89 | // } 90 | // }, 5000); 91 | // } 92 | // updateBannerVisibility(); 93 | // } 94 | // } 95 | 96 | var buildUrl = "Build"; 97 | var loaderUrl = buildUrl + "/WebGL Builds.loader.js"; 98 | var config = { 99 | dataUrl: buildUrl + "/WebGL Builds.data", 100 | frameworkUrl: buildUrl + "/WebGL Builds.framework.js", 101 | codeUrl: buildUrl + "/WebGL Builds.wasm", 102 | streamingAssetsUrl: "StreamingAssets", 103 | companyName: "DefaultCompany", 104 | productName: "web2dTest", 105 | productVersion: "4.0.1", 106 | // showBanner: unityShowBanner, 107 | }; 108 | 109 | // By default Unity keeps WebGL canvas render target size matched with 110 | // the DOM size of the canvas element (scaled by window.devicePixelRatio) 111 | // Set this to false if you want to decouple this synchronization from 112 | // happening inside the engine, and you would instead like to size up 113 | // the canvas DOM size and WebGL render target sizes yourself. 114 | // config.matchWebGLToCanvasSize = false; 115 | 116 | if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) { 117 | // Mobile device style: fill the whole browser client area with the game canvas: 118 | 119 | var meta = document.createElement('meta'); 120 | if (container) { 121 | container.className = "unity-mobile"; 122 | if (canvas) { 123 | canvas.className = "unity-mobile"; 124 | } 125 | 126 | // To lower canvas resolution on mobile devices to gain some 127 | // performance, uncomment the following line: 128 | // config.devicePixelRatio = 1; 129 | 130 | // unityShowBanner('WebGL builds are not supported on mobile devices.', 'warning'); 131 | } 132 | } else { 133 | // Desktop style: Render the game canvas in a window that can be maximized to fullscreen: 134 | if (canvas) { 135 | (canvas as HTMLCanvasElement).style.width = "960px"; 136 | (canvas as HTMLCanvasElement).style.height = "600px"; 137 | } 138 | } 139 | 140 | if (loadingBar) { 141 | (loadingBar as HTMLElement).style.display = "block"; 142 | } 143 | 144 | var script = document.createElement("script"); 145 | script.src = loaderUrl; 146 | script.onload = () => { 147 | createUnityInstance(canvas, config, (progress: number) => { 148 | if (progressBarFull) { 149 | (progressBarFull as HTMLElement).style.width = 100 * progress + "%"; 150 | } 151 | }).then((unityInstance: { SetFullscreen: (arg0: number) => void; }) => { 152 | if (loadingBar) { 153 | (loadingBar as HTMLElement).style.display = "none"; 154 | } 155 | if (fullscreenButton) { 156 | const button = fullscreenButton as HTMLButtonElement; 157 | button.onclick = () => { 158 | unityInstance.SetFullscreen(1); 159 | }; 160 | } 161 | }).catch((message: any) => { 162 | alert(message); 163 | }); 164 | }; 165 | document.body.appendChild(script); 166 | } 167 | /****/ 168 | 169 | 170 | 171 | }, [showGame]); 172 | 173 | return
174 | {showGame ? 175 | 176 |
177 |
178 |
179 | 180 |
181 | 182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 | 191 |

Esta jugando {playerName || "unknown"}

192 | 193 |
194 |
195 | : 196 | 197 | {/* Open */} 198 | 199 | 200 | Ingresa tu nombre 201 | 202 | { 203 | console.log(e.target.value) 204 | setPlayer(e.target.value) 205 | }} /> 206 | 207 | 208 | 209 | {/* Cancel */} 210 | {setShowGame(true)}}>Continue 211 | 212 | 213 | 214 | } 215 | 216 | 217 |
218 | } 219 | -------------------------------------------------------------------------------- /TallerRankingNode/frontend/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "app/globals.css", 9 | "baseColor": "slate", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils" 16 | } 17 | } -------------------------------------------------------------------------------- /TallerRankingNode/frontend/components/ui/alert-dialog.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" 5 | 6 | import { cn } from "@/lib/utils" 7 | import { buttonVariants } from "@/components/ui/button" 8 | 9 | const AlertDialog = AlertDialogPrimitive.Root 10 | 11 | const AlertDialogTrigger = AlertDialogPrimitive.Trigger 12 | 13 | const AlertDialogPortal = AlertDialogPrimitive.Portal 14 | 15 | const AlertDialogOverlay = React.forwardRef< 16 | React.ElementRef, 17 | React.ComponentPropsWithoutRef 18 | >(({ className, ...props }, ref) => ( 19 | 27 | )) 28 | AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName 29 | 30 | const AlertDialogContent = React.forwardRef< 31 | React.ElementRef, 32 | React.ComponentPropsWithoutRef 33 | >(({ className, ...props }, ref) => ( 34 | 35 | 36 | 44 | 45 | )) 46 | AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName 47 | 48 | const AlertDialogHeader = ({ 49 | className, 50 | ...props 51 | }: React.HTMLAttributes) => ( 52 |
59 | ) 60 | AlertDialogHeader.displayName = "AlertDialogHeader" 61 | 62 | const AlertDialogFooter = ({ 63 | className, 64 | ...props 65 | }: React.HTMLAttributes) => ( 66 |
73 | ) 74 | AlertDialogFooter.displayName = "AlertDialogFooter" 75 | 76 | const AlertDialogTitle = React.forwardRef< 77 | React.ElementRef, 78 | React.ComponentPropsWithoutRef 79 | >(({ className, ...props }, ref) => ( 80 | 85 | )) 86 | AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName 87 | 88 | const AlertDialogDescription = React.forwardRef< 89 | React.ElementRef, 90 | React.ComponentPropsWithoutRef 91 | >(({ className, ...props }, ref) => ( 92 | 97 | )) 98 | AlertDialogDescription.displayName = 99 | AlertDialogPrimitive.Description.displayName 100 | 101 | const AlertDialogAction = React.forwardRef< 102 | React.ElementRef, 103 | React.ComponentPropsWithoutRef 104 | >(({ className, ...props }, ref) => ( 105 | 110 | )) 111 | AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName 112 | 113 | const AlertDialogCancel = React.forwardRef< 114 | React.ElementRef, 115 | React.ComponentPropsWithoutRef 116 | >(({ className, ...props }, ref) => ( 117 | 126 | )) 127 | AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName 128 | 129 | export { 130 | AlertDialog, 131 | AlertDialogPortal, 132 | AlertDialogOverlay, 133 | AlertDialogTrigger, 134 | AlertDialogContent, 135 | AlertDialogHeader, 136 | AlertDialogFooter, 137 | AlertDialogTitle, 138 | AlertDialogDescription, 139 | AlertDialogAction, 140 | AlertDialogCancel, 141 | } 142 | -------------------------------------------------------------------------------- /TallerRankingNode/frontend/components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { Slot } from "@radix-ui/react-slot" 3 | import { cva, type VariantProps } from "class-variance-authority" 4 | 5 | import { cn } from "@/lib/utils" 6 | 7 | const buttonVariants = cva( 8 | "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", 9 | { 10 | variants: { 11 | variant: { 12 | default: "bg-primary text-primary-foreground hover:bg-primary/90", 13 | destructive: 14 | "bg-destructive text-destructive-foreground hover:bg-destructive/90", 15 | outline: 16 | "border border-input bg-background hover:bg-accent hover:text-accent-foreground", 17 | secondary: 18 | "bg-secondary text-secondary-foreground hover:bg-secondary/80", 19 | ghost: "hover:bg-accent hover:text-accent-foreground", 20 | link: "text-primary underline-offset-4 hover:underline", 21 | }, 22 | size: { 23 | default: "h-10 px-4 py-2", 24 | sm: "h-9 rounded-md px-3", 25 | lg: "h-11 rounded-md px-8", 26 | icon: "h-10 w-10", 27 | }, 28 | }, 29 | defaultVariants: { 30 | variant: "default", 31 | size: "default", 32 | }, 33 | } 34 | ) 35 | 36 | export interface ButtonProps 37 | extends React.ButtonHTMLAttributes, 38 | VariantProps { 39 | asChild?: boolean 40 | } 41 | 42 | const Button = React.forwardRef( 43 | ({ className, variant, size, asChild = false, ...props }, ref) => { 44 | const Comp = asChild ? Slot : "button" 45 | return ( 46 | 51 | ) 52 | } 53 | ) 54 | Button.displayName = "Button" 55 | 56 | export { Button, buttonVariants } 57 | -------------------------------------------------------------------------------- /TallerRankingNode/frontend/dependencies.txt: -------------------------------------------------------------------------------- 1 | com.unity.cinemachine@2.8.9 2 | com.unity.collab-proxy@1.17.6 3 | com.unity.connect.share@4.2.3 4 | com.unity.feature.development@1.0.1 5 | com.unity.ide.rider@3.0.15 6 | com.unity.ide.visualstudio@2.0.16 7 | com.unity.ide.vscode@1.2.5 8 | com.unity.learn.iet-framework@2.2.2 9 | com.unity.render-pipelines.universal@12.1.7 10 | com.unity.test-framework@1.1.31 11 | com.unity.textmeshpro@3.0.6 12 | com.unity.timeline@1.6.4 13 | com.unity.ugui@1.0.0 14 | com.unity.visualscripting@1.7.8 15 | com.unity.modules.ai@1.0.0 16 | com.unity.modules.androidjni@1.0.0 17 | com.unity.modules.animation@1.0.0 18 | com.unity.modules.assetbundle@1.0.0 19 | com.unity.modules.audio@1.0.0 20 | com.unity.modules.cloth@1.0.0 21 | com.unity.modules.director@1.0.0 22 | com.unity.modules.imageconversion@1.0.0 23 | com.unity.modules.imgui@1.0.0 24 | com.unity.modules.jsonserialize@1.0.0 25 | com.unity.modules.particlesystem@1.0.0 26 | com.unity.modules.physics@1.0.0 27 | com.unity.modules.physics2d@1.0.0 28 | com.unity.modules.screencapture@1.0.0 29 | com.unity.modules.terrain@1.0.0 30 | com.unity.modules.terrainphysics@1.0.0 31 | com.unity.modules.tilemap@1.0.0 32 | com.unity.modules.ui@1.0.0 33 | com.unity.modules.uielements@1.0.0 34 | com.unity.modules.umbra@1.0.0 35 | com.unity.modules.unityanalytics@1.0.0 36 | com.unity.modules.unitywebrequest@1.0.0 37 | com.unity.modules.unitywebrequestassetbundle@1.0.0 38 | com.unity.modules.unitywebrequestaudio@1.0.0 39 | com.unity.modules.unitywebrequesttexture@1.0.0 40 | com.unity.modules.unitywebrequestwww@1.0.0 41 | com.unity.modules.vehicles@1.0.0 42 | com.unity.modules.video@1.0.0 43 | com.unity.modules.vr@1.0.0 44 | com.unity.modules.wind@1.0.0 45 | com.unity.modules.xr@1.0.0 46 | com.unity.template.platformer@4.0.1 47 | -------------------------------------------------------------------------------- /TallerRankingNode/frontend/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /TallerRankingNode/frontend/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: false, 4 | }; 5 | 6 | export default nextConfig; 7 | -------------------------------------------------------------------------------- /TallerRankingNode/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wasd-game-techschool", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@radix-ui/react-alert-dialog": "^1.0.5", 13 | "@radix-ui/react-slot": "^1.0.2", 14 | "class-variance-authority": "^0.7.0", 15 | "clsx": "^2.1.0", 16 | "lucide-react": "^0.364.0", 17 | "next": "^14.2.21", 18 | "react": "^18", 19 | "react-dom": "^18", 20 | "tailwind-merge": "^2.2.2", 21 | "tailwindcss-animate": "^1.0.7" 22 | }, 23 | "devDependencies": { 24 | "@types/node": "^20", 25 | "@types/react": "^18", 26 | "@types/react-dom": "^18", 27 | "autoprefixer": "^10.0.1", 28 | "eslint": "^8", 29 | "eslint-config-next": "14.1.0", 30 | "postcss": "^8", 31 | "tailwindcss": "^3.3.0", 32 | "typescript": "^5" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /TallerRankingNode/frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /TallerRankingNode/frontend/public/Build/WebGL Builds.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerRankingNode/frontend/public/Build/WebGL Builds.data -------------------------------------------------------------------------------- /TallerRankingNode/frontend/public/Build/WebGL Builds.loader.js: -------------------------------------------------------------------------------- 1 | function createUnityInstance(e,t,r){function n(e,r){if(!n.aborted&&t.showBanner)return"error"==r&&(n.aborted=!0),t.showBanner(e,r);switch(r){case"error":console.error(e);break;case"warning":console.warn(e);break;default:console.log(e)}}function o(e){var t=e.reason||e.error,r=t?t.toString():e.message||e.reason||"",n=t&&t.stack?t.stack.toString():"";if(n.startsWith(r)&&(n=n.substring(r.length)),r+="\n"+n.trim(),r&&f.stackTraceRegExp&&f.stackTraceRegExp.test(r)){var o=e.filename||t&&(t.fileName||t.sourceURL)||"",a=e.lineno||t&&(t.lineNumber||t.line)||0;i(r,o,a)}}function a(e,t,r){var n=e[t];"undefined"!=typeof n&&n||(console.warn('Config option "'+t+'" is missing or empty. Falling back to default value: "'+r+'". Consider updating your WebGL template to include the missing config option.'),e[t]=r)}function s(e){e.preventDefault()}function i(e,t,r){if(e.indexOf("fullscreen error")==-1){if(f.startupErrorHandler)return void f.startupErrorHandler(e,t,r);if(!(f.errorHandler&&f.errorHandler(e,t,r)||(console.log("Invoking error handler due to\n"+e),"function"==typeof dump&&dump("Invoking error handler due to\n"+e),i.didShowErrorMessage))){var e="An error occurred running the Unity content on this page. See your browser JavaScript console for more info. The error was:\n"+e;e.indexOf("DISABLE_EXCEPTION_CATCHING")!=-1?e="An exception has occurred, but exception handling has been disabled in this build. If you are the developer of this content, enable exceptions in your project WebGL player settings to be able to catch the exception or see the stack trace.":e.indexOf("Cannot enlarge memory arrays")!=-1?e="Out of memory. If you are the developer of this content, try allocating more memory to your WebGL build in the WebGL player settings.":e.indexOf("Invalid array buffer length")==-1&&e.indexOf("Invalid typed array length")==-1&&e.indexOf("out of memory")==-1&&e.indexOf("could not allocate memory")==-1||(e="The browser could not allocate enough memory for the WebGL content. If you are the developer of this content, try allocating less memory to your WebGL build in the WebGL player settings."),alert(e),i.didShowErrorMessage=!0}}}function d(e,t){if("symbolsUrl"!=e){var n=f.downloadProgress[e];n||(n=f.downloadProgress[e]={started:!1,finished:!1,lengthComputable:!1,total:0,loaded:0}),"object"!=typeof t||"progress"!=t.type&&"load"!=t.type||(n.started||(n.started=!0,n.lengthComputable=t.lengthComputable),n.total=t.total,n.loaded=t.loaded,"load"==t.type&&(n.finished=!0));var o=0,a=0,s=0,i=0,d=0;for(var e in f.downloadProgress){var n=f.downloadProgress[e];if(!n.started)return 0;s++,n.lengthComputable?(o+=n.loaded,a+=n.total,i++):n.finished||d++}var u=s?(s-d-(a?i*(a-o)/a:0))/s:0;r(.9*u)}}function u(e){d(e);var t=f.cacheControl(f[e]),r=f.companyName&&f.productName?f.cachedFetch:f.fetchWithProgress,o=f[e],a=/file:\/\//.exec(o)?"same-origin":void 0,s=r(f[e],{method:"GET",companyName:f.companyName,productName:f.productName,control:t,mode:a,onProgress:function(t){d(e,t)}});return s.then(function(e){return e.parsedBody}).catch(function(t){var r="Failed to download file "+f[e];"file:"==location.protocol?n(r+". Loading web pages via a file:// URL without a web server is not supported by this browser. Please use a local development web server to host Unity content, or use the Unity Build and Run option.","error"):console.error(r)})}function l(){return new Promise(function(e,t){var r=document.createElement("script");r.src=f.frameworkUrl,r.onload=function(){if("undefined"==typeof unityFramework||!unityFramework){var t=[["br","br"],["gz","gzip"]];for(var o in t){var a=t[o];if(f.frameworkUrl.endsWith("."+a[0])){var s="Unable to parse "+f.frameworkUrl+"!";if("file:"==location.protocol)return void n(s+" Loading pre-compressed (brotli or gzip) content via a file:// URL without a web server is not supported by this browser. Please use a local development web server to host compressed Unity content, or use the Unity Build and Run option.","error");if(s+=' This can happen if build compression was enabled but web server hosting the content was misconfigured to not serve the file with HTTP Response Header "Content-Encoding: '+a[1]+'" present. Check browser Console and Devtools Network tab to debug.',"br"==a[0]&&"http:"==location.protocol){var i=["localhost","127.0.0.1"].indexOf(location.hostname)!=-1?"":"Migrate your server to use HTTPS.";s=/Firefox/.test(navigator.userAgent)?"Unable to parse "+f.frameworkUrl+'!
If using custom web server, verify that web server is sending .br files with HTTP Response Header "Content-Encoding: br". Brotli compression may not be supported in Firefox over HTTP connections. '+i+' See https://bugzilla.mozilla.org/show_bug.cgi?id=1670675 for more information.':"Unable to parse "+f.frameworkUrl+'!
If using custom web server, verify that web server is sending .br files with HTTP Response Header "Content-Encoding: br". Brotli compression may not be supported over HTTP connections. Migrate your server to use HTTPS.'}return void n(s,"error")}}n("Unable to parse "+f.frameworkUrl+"! The file is corrupt, or compression was misconfigured? (check Content-Encoding HTTP Response Header on web server)","error")}var d=unityFramework;unityFramework=null,r.onload=null,e(d)},r.onerror=function(e){n("Unable to load file "+f.frameworkUrl+"! Check that the file exists on the remote server. (also check browser Console and Devtools Network tab to debug)","error")},document.body.appendChild(r),f.deinitializers.push(function(){document.body.removeChild(r)})})}function c(){l().then(function(e){e(f)});var e=u("dataUrl");f.preRun.push(function(){f.addRunDependency("dataUrl"),e.then(function(e){var t=new DataView(e.buffer,e.byteOffset,e.byteLength),r=0,n="UnityWebData1.0\0";if(!String.fromCharCode.apply(null,e.subarray(r,r+n.length))==n)throw"unknown data format";r+=n.length;var o=t.getUint32(r,!0);for(r+=4;r0;u=l,l=d.indexOf("/",u)+1)f.FS_createPath(d.substring(0,u),d.substring(u,l-1),!0,!0);f.FS_createDataFile(d,null,e.subarray(a,a+s),!0,!0,!0)}f.removeRunDependency("dataUrl")})})}r=r||function(){};var f={canvas:e,webglContextAttributes:{preserveDrawingBuffer:!1,powerPreference:1},cacheControl:function(e){return e==f.dataUrl?"must-revalidate":"no-store"},streamingAssetsUrl:"StreamingAssets",downloadProgress:{},deinitializers:[],intervals:{},setInterval:function(e,t){var r=window.setInterval(e,t);return this.intervals[r]=!0,r},clearInterval:function(e){delete this.intervals[e],window.clearInterval(e)},preRun:[],postRun:[],print:function(e){console.log(e)},printErr:function(e){console.error(e),"string"==typeof e&&e.indexOf("wasm streaming compile failed")!=-1&&(e.toLowerCase().indexOf("mime")!=-1?n('HTTP Response Header "Content-Type" configured incorrectly on the server for file '+f.codeUrl+' , should be "application/wasm". Startup time performance will suffer.',"warning"):n('WebAssembly streaming compilation failed! This can happen for example if "Content-Encoding" HTTP header is incorrectly enabled on the server for file '+f.codeUrl+", but the file is not pre-compressed on disk (or vice versa). Check the Network tab in browser Devtools to debug server header configuration.","warning"))},locateFile:function(e){return"build.wasm"==e?this.codeUrl:e},disabledCanvasEvents:["contextmenu","dragstart"]};a(t,"companyName","Unity"),a(t,"productName","WebGL Player"),a(t,"productVersion","1.0");for(var h in t)f[h]=t[h];f.streamingAssetsUrl=new URL(f.streamingAssetsUrl,document.URL).href;var p=f.disabledCanvasEvents.slice();p.forEach(function(t){e.addEventListener(t,s)}),window.addEventListener("error",o),window.addEventListener("unhandledrejection",o),f.deinitializers.push(function(){f.disableAccessToMediaDevices(),p.forEach(function(t){e.removeEventListener(t,s)}),window.removeEventListener("error",o),window.removeEventListener("unhandledrejection",o);for(var t in f.intervals)window.clearInterval(t);f.intervals={}}),f.QuitCleanup=function(){for(var e=0;e=200&&this.status<=299}.bind(this)})}function o(e,t,r,n,o){var a={url:e,version:d.version,company:t,product:r,updated:n,revalidated:n,accessed:n,response:{headers:{}}};return o&&(o.headers.forEach(function(e,t){a.response.headers[t]=e}),["redirected","status","statusText","type","url"].forEach(function(e){a.response[e]=o[e]}),a.response.parsedBody=o.parsedBody),a}function a(e,t){return(!t||!t.method||"GET"===t.method)&&((!t||["must-revalidate","immutable"].indexOf(t.control)!=-1)&&!!e.match("^https?://"))}function s(s,l){function c(t,r){return u(t,r).then(function(t){return!g.enabled||g.revalidated?t:304===t.status?(g.result.revalidated=g.result.accessed,g.revalidated=!0,h.storeRequest(g.result).then(function(){e("'"+g.result.url+"' successfully revalidated and served from the indexedDB cache")}).catch(function(t){e("'"+g.result.url+"' successfully revalidated but not stored in the indexedDB cache due to the error: "+t)}),new n(g.result.response)):(200==t.status?(g.result=o(t.url,g.company,g.product,g.accessed,t),g.revalidated=!0,h.storeRequest(g.result).then(function(){e("'"+g.result.url+"' successfully downloaded and stored in the indexedDB cache")}).catch(function(t){e("'"+g.result.url+"' successfully downloaded but not stored in the indexedDB cache due to the error: "+t)})):e("'"+g.result.url+"' request failed with status: "+t.status+" "+t.statusText),t)})}function f(e){l&&l.onProgress&&(l.onProgress({type:"progress",total:e.parsedBody.length,loaded:e.parsedBody.length,lengthComputable:!0}),l.onProgress({type:"load",total:e.parsedBody.length,loaded:e.parsedBody.length,lengthComputable:!0}))}var h=i.getInstance(),p=t("string"==typeof s?s:s.url),g={enabled:a(p,l)};return l&&(g.control=l.control,g.company=l.company,g.product=l.product),g.result=o(p,g.company,g.product,Date.now()),g.revalidated=!1,g.enabled?h.loadRequest(g.result.url).then(function(t){if(!t||t.version!==d.version)return c(s,l);g.result=t,g.result.accessed=Date.now();var o=new n(g.result.response);if("immutable"==g.control)return g.revalidated=!0,h.storeRequest(g.result),e("'"+g.result.url+"' served from the indexedDB cache without revalidation"),f(o),o;if(r(g.result.url)&&(o.headers.get("Last-Modified")||o.headers.get("ETag")))return fetch(g.result.url,{method:"HEAD"}).then(function(t){return g.revalidated=["Last-Modified","ETag"].every(function(e){return!o.headers.get(e)||o.headers.get(e)==t.headers.get(e)}),g.revalidated?(g.result.revalidated=g.result.accessed,h.storeRequest(g.result),e("'"+g.result.url+"' successfully revalidated and served from the indexedDB cache"),f(o),o):c(s,l)});l=l||{};var a=l.headers||{};return l.headers=a,o.headers.get("Last-Modified")?(a["If-Modified-Since"]=o.headers.get("Last-Modified"),a["Cache-Control"]="no-cache"):o.headers.get("ETag")&&(a["If-None-Match"]=o.headers.get("ETag"),a["Cache-Control"]="no-cache"),c(s,l)}).catch(function(t){return e("Failed to load '"+g.result.url+"' from indexedDB cache due to the error: "+t),u(s,l)}):u(s,l)}var i=f.UnityCache,d=i.RequestStore,u=f.fetchWithProgress;return n.prototype.arrayBuffer=function(){return Promise.resolve(this.parsedBody.buffer)},n.prototype.blob=function(){return this.arrayBuffer().then(function(e){return new Blob([e])})},n.prototype.json=function(){return this.text().then(function(e){return JSON.parse(e)})},n.prototype.text=function(){var e=new TextDecoder;return Promise.resolve(e.decode(this.parsedBody))},s}(),new Promise(function(e,t){f.SystemInfo.hasWebGL?1==f.SystemInfo.hasWebGL?t('Your browser does not support graphics API "WebGL 2" which is required for this content.'):f.SystemInfo.hasWasm?(1==f.SystemInfo.hasWebGL&&f.print('Warning: Your browser does not support "WebGL 2" Graphics API, switching to "WebGL 1"'),f.startupErrorHandler=t,r(0),f.postRun.push(function(){r(1),delete f.startupErrorHandler,e(b)}),c()):t("Your browser does not support WebAssembly."):t("Your browser does not support WebGL.")})} -------------------------------------------------------------------------------- /TallerRankingNode/frontend/public/Build/WebGL Builds.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerRankingNode/frontend/public/Build/WebGL Builds.wasm -------------------------------------------------------------------------------- /TallerRankingNode/frontend/public/StreamingAssets/UnityServicesProjectConfiguration.json: -------------------------------------------------------------------------------- 1 | {"Keys":["com.unity.services.core.cloud-environment","com.unity.services.core.version","com.unity.services.core.initializer-assembly-qualified-names","com.unity.services.core.all-package-names"],"Values":[{"m_Value":"production","m_IsReadOnly":false},{"m_Value":"1.5.2","m_IsReadOnly":true},{"m_Value":"Unity.Services.Core.Registration.CorePackageInitializer, Unity.Services.Core.Registration, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null","m_IsReadOnly":true},{"m_Value":"com.unity.services.core","m_IsReadOnly":false}]} -------------------------------------------------------------------------------- /TallerRankingNode/frontend/public/TemplateData/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerRankingNode/frontend/public/TemplateData/favicon.ico -------------------------------------------------------------------------------- /TallerRankingNode/frontend/public/TemplateData/fullscreen-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerRankingNode/frontend/public/TemplateData/fullscreen-button.png -------------------------------------------------------------------------------- /TallerRankingNode/frontend/public/TemplateData/progress-bar-empty-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerRankingNode/frontend/public/TemplateData/progress-bar-empty-dark.png -------------------------------------------------------------------------------- /TallerRankingNode/frontend/public/TemplateData/progress-bar-empty-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerRankingNode/frontend/public/TemplateData/progress-bar-empty-light.png -------------------------------------------------------------------------------- /TallerRankingNode/frontend/public/TemplateData/progress-bar-full-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerRankingNode/frontend/public/TemplateData/progress-bar-full-dark.png -------------------------------------------------------------------------------- /TallerRankingNode/frontend/public/TemplateData/progress-bar-full-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerRankingNode/frontend/public/TemplateData/progress-bar-full-light.png -------------------------------------------------------------------------------- /TallerRankingNode/frontend/public/TemplateData/style.css: -------------------------------------------------------------------------------- 1 | body { padding: 0; margin: 0 } 2 | /* #unity-container { position: absolute } */ 3 | /* #unity-container.unity-desktop { left: 30%; top: 50%; transform: translate(-50%, -50%) } 4 | #unity-container.unity-mobile { width: 100%; height: 100% } */ 5 | #unity-canvas { background: #231F20 } 6 | /* .unity-mobile #unity-canvas { width: 100%; height: 100% } */ 7 | #unity-loading-bar { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); display: none } 8 | #unity-logo { width: 154px; height: 130px; background: url('unity-logo-dark.png') no-repeat center } 9 | #unity-progress-bar-empty { width: 141px; height: 18px; margin-top: 10px; margin-left: 6.5px; background: url('progress-bar-empty-dark.png') no-repeat center } 10 | #unity-progress-bar-full { width: 0%; height: 18px; margin-top: 10px; background: url('progress-bar-full-dark.png') no-repeat center } 11 | #unity-footer { position: relative } 12 | .unity-mobile #unity-footer { display: none } 13 | #unity-webgl-logo { float:left; width: 204px; height: 38px; background: url('webgl-logo.png') no-repeat center } 14 | #unity-build-title { float: right; margin-right: 10px; line-height: 38px; font-family: arial; font-size: 18px } 15 | #unity-fullscreen-button { float: right; width: 38px; height: 38px; background: url('fullscreen-button.png') no-repeat center } 16 | #unity-warning { position: absolute; left: 50%; top: 5%; transform: translate(-50%); background: white; padding: 10px; display: none } 17 | -------------------------------------------------------------------------------- /TallerRankingNode/frontend/public/TemplateData/unity-logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerRankingNode/frontend/public/TemplateData/unity-logo-dark.png -------------------------------------------------------------------------------- /TallerRankingNode/frontend/public/TemplateData/unity-logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerRankingNode/frontend/public/TemplateData/unity-logo-light.png -------------------------------------------------------------------------------- /TallerRankingNode/frontend/public/TemplateData/webgl-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerRankingNode/frontend/public/TemplateData/webgl-logo.png -------------------------------------------------------------------------------- /TallerRankingNode/frontend/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TallerRankingNode/frontend/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TallerRankingNode/frontend/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss" 2 | 3 | const config = { 4 | darkMode: ["class"], 5 | content: [ 6 | './pages/**/*.{ts,tsx}', 7 | './components/**/*.{ts,tsx}', 8 | './app/**/*.{ts,tsx}', 9 | './src/**/*.{ts,tsx}', 10 | ], 11 | prefix: "", 12 | theme: { 13 | container: { 14 | center: true, 15 | padding: "2rem", 16 | screens: { 17 | "2xl": "1400px", 18 | }, 19 | }, 20 | extend: { 21 | colors: { 22 | border: "hsl(var(--border))", 23 | input: "hsl(var(--input))", 24 | ring: "hsl(var(--ring))", 25 | background: "hsl(var(--background))", 26 | foreground: "hsl(var(--foreground))", 27 | primary: { 28 | DEFAULT: "hsl(var(--primary))", 29 | foreground: "hsl(var(--primary-foreground))", 30 | }, 31 | secondary: { 32 | DEFAULT: "hsl(var(--secondary))", 33 | foreground: "hsl(var(--secondary-foreground))", 34 | }, 35 | destructive: { 36 | DEFAULT: "hsl(var(--destructive))", 37 | foreground: "hsl(var(--destructive-foreground))", 38 | }, 39 | muted: { 40 | DEFAULT: "hsl(var(--muted))", 41 | foreground: "hsl(var(--muted-foreground))", 42 | }, 43 | accent: { 44 | DEFAULT: "hsl(var(--accent))", 45 | foreground: "hsl(var(--accent-foreground))", 46 | }, 47 | popover: { 48 | DEFAULT: "hsl(var(--popover))", 49 | foreground: "hsl(var(--popover-foreground))", 50 | }, 51 | card: { 52 | DEFAULT: "hsl(var(--card))", 53 | foreground: "hsl(var(--card-foreground))", 54 | }, 55 | }, 56 | borderRadius: { 57 | lg: "var(--radius)", 58 | md: "calc(var(--radius) - 2px)", 59 | sm: "calc(var(--radius) - 4px)", 60 | }, 61 | keyframes: { 62 | "accordion-down": { 63 | from: { height: "0" }, 64 | to: { height: "var(--radix-accordion-content-height)" }, 65 | }, 66 | "accordion-up": { 67 | from: { height: "var(--radix-accordion-content-height)" }, 68 | to: { height: "0" }, 69 | }, 70 | }, 71 | animation: { 72 | "accordion-down": "accordion-down 0.2s ease-out", 73 | "accordion-up": "accordion-up 0.2s ease-out", 74 | }, 75 | }, 76 | }, 77 | plugins: [require("tailwindcss-animate")], 78 | } satisfies Config 79 | 80 | export default config -------------------------------------------------------------------------------- /TallerRankingNode/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "incremental": true, 15 | "plugins": [ 16 | { 17 | "name": "next" 18 | } 19 | ], 20 | "paths": { 21 | "@/*": ["./*"] 22 | } 23 | }, 24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 25 | "exclude": ["node_modules"] 26 | } 27 | -------------------------------------------------------------------------------- /TallerReact/Escuela de React.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerReact/Escuela de React.pdf -------------------------------------------------------------------------------- /TallerReact/MaterialDeApoyo.md: -------------------------------------------------------------------------------- 1 | # Material De Apoyo 2 | 3 | Durante el taller utilizaremos las siguientes herramientas para construir nuestra PokeDex, te dejo enlaces útiles en donde puedes familiarizarte un poco con ellas antes de asistir al taller: 4 | 5 | - [PokeApi](https://pokeapi.co/), para obtener la información de los pokemons 6 | - [fetch](https://didacticode.com/que-es-la-api-fetch-de-javascrtip/), para obtener los datos de la API 7 | - Trabajaremos un poco con los hooks [useState](https://es.react.dev/learn/state-a-components-memory) para manejo del estado y [useEffect](https://es.react.dev/reference/react/useEffect#fetching-data-with-effects) para el llamado a la API 8 | - [Material UI](https://mui.com/material-ui/getting-started/) para dar estilos a nuestra app 9 | - [React Router](https://reactrouter.com/en/main/start/tutorial) para crear las rutas 10 | - [React Lazy Load Image Component](https://www.npmjs.com/package/react-lazy-load-image-component) para hacer [carga diferida](https://css-tianguis.com/lazy-loading-o-carga-diferida-de-imagenes-como-mejorar-la-velocidad-de-nuestros-sitios/) de las imágenes 11 | - [Material adicional a usar durante el taller](https://alais29dev.notion.site/Escuela-de-React-Material-de-Apoyo-3dbe38f0e89143888c8252acc07d5b45?pvs=4) 12 | -------------------------------------------------------------------------------- /TallerReact/README.md: -------------------------------------------------------------------------------- 1 | # Taller: Desarrollando una Pokedex con React 2 | 3 | **Mentor de esta edición:** [Nombre del Mentor] 4 | 5 | ## Descripción del Taller 6 | En este taller, te embarcarás en la emocionante tarea de desarrollar tu propia Pokedex utilizando React. Aprenderás cómo conectar tu aplicación a una API externa para obtener datos de diferentes Pokemon y mostrarlos en tu Pokedex. 7 | 8 | ## Objetivo del Taller 9 | El propósito principal de este taller es que cada participante pueda entender y aplicar los conceptos básicos de React y la conexión con APIs externas. Al final del taller, cada participante debería tener una Pokedex funcional, desarrollada con React. 10 | 11 | ## Prerrequisitos 12 | - Conocimientos en JavaScript. 13 | - Cuenta activa en GitHub. 14 | - Tener instalado Node.js y npm en tu laptop. 15 | - Laptop con un editor de texto. 16 | 17 | ## Material de apoyo 18 | Dentro de esta carpeta encontrarás archivos, guías y recursos que te serán de gran utilidad durante el taller. Te recomendamos descargar y revisar estos materiales con anticipación para aprovechar al máximo la sesión. 19 | 20 | --- 21 | 22 | Esperamos que disfrutes desarrollando tu Pokedex y profundizando en el maravilloso mundo de React. Si te surgen preguntas o inquietudes, no dudes en abrir un issue en este repositorio o contactar directamente al mentor de esta edición. 23 | 24 | ¡Atrápalos a todos y diviértete programando! 25 | -------------------------------------------------------------------------------- /TallerReact/pokedex-app/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:react/recommended', 7 | 'plugin:react/jsx-runtime', 8 | 'plugin:react-hooks/recommended', 9 | ], 10 | ignorePatterns: ['dist', '.eslintrc.cjs'], 11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, 12 | settings: { react: { version: '18.2' } }, 13 | plugins: ['react-refresh'], 14 | rules: { 15 | 'react-refresh/only-export-components': [ 16 | 'warn', 17 | { allowConstantExport: true }, 18 | ], 19 | }, 20 | } 21 | -------------------------------------------------------------------------------- /TallerReact/pokedex-app/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /TallerReact/pokedex-app/README.md: -------------------------------------------------------------------------------- 1 |

Welcome to PokeDex App 👋

2 |

3 | Version 4 | 5 | 6 | 7 | Documentation 8 | 9 | 10 | Maintenance 11 | 12 |

13 | 14 | > Simple Pokedex app built with React, Vite, Material UI and React Router. Pokemon data is gotten from [PokeAPI](https://pokeapi.co/) 15 | 16 | ### 🏠 [Homepage](https://github.com/Alais29/pokedex-techschool#readme) 17 | 18 | ## Prerequisites 19 | 20 | - npm >=9.6.4 21 | - node >=18.4.0 22 | 23 | ## Install 24 | 25 | ```sh 26 | npm install 27 | ``` 28 | 29 | ## Usage 30 | 31 | ```sh 32 | npm run dev 33 | ``` 34 | 35 | ## Features 36 | 37 | - Page that lists pokemons, starting at 50, with infinite scrolling until getting all pokemons from the PokeAPI 38 | - A details page that shows stats, types, abilities and moves from the pokemon. 39 | - All styles applied with Material UI and styled components 40 | 41 | ## Author 42 | 43 | 👤 **Alfonsina Lizardo** 44 | 45 | - Website: https://alfonsinalizardo.netlify.app 46 | - GitHub: [@Alais29](https://github.com/Alais29) 47 | - LinkedIn: [@alfonsinalizardo](https://linkedin.com/in/alfonsinalizardo) 48 | - Instagram: [@Alais29.dev](https://www.instagram.com/alais29.dev/) 49 | - Threads: [@Alais29.dev](https://www.threads.net/@alais29.dev) 50 | 51 | ## Show your support 52 | 53 | Give a ⭐️ if this project helped you! 54 | 55 | --- 56 | 57 | _This README was generated with ❤️ by [readme-md-generator](https://github.com/kefranabg/readme-md-generator)_ 58 | -------------------------------------------------------------------------------- /TallerReact/pokedex-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /TallerReact/pokedex-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pokedex-react", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "Simple Pokedex app built using React, Vite, Material UI and React Router. Pokemon data is gotten from PokeAPI", 6 | "author": "Alfonsina Lizardo", 7 | "homepage": "https://github.com/Alais29/pokedex-techschool#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/Alais29/pokedex-techschool.git" 11 | }, 12 | "engines": { 13 | "npm": ">=9.6.4", 14 | "node": ">=18.4.0" 15 | }, 16 | "type": "module", 17 | "scripts": { 18 | "dev": "vite", 19 | "build": "vite build", 20 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", 21 | "preview": "vite preview" 22 | }, 23 | "dependencies": { 24 | "@emotion/react": "^11.11.1", 25 | "@emotion/styled": "^11.11.0", 26 | "@fontsource/press-start-2p": "^5.0.17", 27 | "@fontsource/roboto": "^5.0.8", 28 | "@mui/icons-material": "^5.14.14", 29 | "@mui/material": "^5.14.14", 30 | "react": "^18.2.0", 31 | "react-dom": "^18.2.0", 32 | "react-infinite-scroll-component": "^6.1.0", 33 | "react-lazy-load-image-component": "^1.6.0", 34 | "react-router-dom": "^6.17.0" 35 | }, 36 | "devDependencies": { 37 | "@types/react": "^18.2.15", 38 | "@types/react-dom": "^18.2.7", 39 | "@vitejs/plugin-react": "^4.0.3", 40 | "eslint": "^8.45.0", 41 | "eslint-plugin-react": "^7.32.2", 42 | "eslint-plugin-react-hooks": "^4.6.0", 43 | "eslint-plugin-react-refresh": "^0.4.3", 44 | "vite": "^4.5.9" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /TallerReact/pokedex-app/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TallerReact/pokedex-app/src/assets/Image_not_available.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerReact/pokedex-app/src/assets/Image_not_available.png -------------------------------------------------------------------------------- /TallerReact/pokedex-app/src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TallerReact/pokedex-app/src/components/Header.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | import AppBar from "@mui/material/AppBar"; 3 | import Toolbar from "@mui/material/Toolbar"; 4 | import Typography from "@mui/material/Typography"; 5 | import Box from "@mui/material/Box"; 6 | import { styled } from "@mui/material/styles"; 7 | import Button from "@mui/material/Button"; 8 | 9 | const CustomLink = styled(Link)` 10 | text-decoration: none; 11 | color: white; 12 | `; 13 | 14 | const Header = (props) => { 15 | return ( 16 | 17 | 18 | 19 | {props.showHomeBtn && ( 20 | 23 | )} 24 | 29 | {props.title} 30 | 31 | 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default Header; 38 | -------------------------------------------------------------------------------- /TallerReact/pokedex-app/src/components/PokemonCard.jsx: -------------------------------------------------------------------------------- 1 | import { LazyLoadImage } from "react-lazy-load-image-component"; 2 | import ImgNotAvailable from "../assets/Image_not_available.png"; 3 | import Card from "@mui/material/Card"; 4 | import CardContent from "@mui/material/CardContent"; 5 | import CardMedia from "@mui/material/CardMedia"; 6 | import Typography from "@mui/material/Typography"; 7 | import CircularProgress from "@mui/material/CircularProgress"; 8 | import { CardActionArea } from "@mui/material"; 9 | 10 | const PokemonCard = (props) => { 11 | return ( 12 | 13 | 20 | 26 | (e.target.src = ImgNotAvailable)} 30 | width="96px" 31 | height="96px" 32 | placeholder={} 33 | /> 34 | 35 | 36 | 43 | {props.pokemonNumber}. {props.pokemonName} 44 | 45 | 46 | 47 | 48 | ); 49 | }; 50 | 51 | export default PokemonCard; 52 | -------------------------------------------------------------------------------- /TallerReact/pokedex-app/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import Root from "./routes/Root.element.jsx"; 4 | import { loader as rootLoader } from "./routes/Root.loader.js"; 5 | import { loader as pokemonDetailsLoader } from "./routes/PokemonDetails.loader.js"; 6 | import { createBrowserRouter, RouterProvider } from "react-router-dom"; 7 | import PokemonDetails from "./routes/PokemonDetails.element.jsx"; 8 | import "@fontsource/roboto/300.css"; 9 | import "@fontsource/roboto/400.css"; 10 | import "@fontsource/roboto/500.css"; 11 | import "@fontsource/roboto/700.css"; 12 | import "@fontsource/press-start-2p"; 13 | import { CssBaseline, createTheme, ThemeProvider } from "@mui/material"; 14 | 15 | const theme = createTheme({ 16 | typography: { 17 | fontFamily: ["'Press Start 2P'", "'Roboto'", "sans-serif"].join(","), 18 | }, 19 | }); 20 | 21 | const router = createBrowserRouter([ 22 | { 23 | path: "/", 24 | element: , 25 | loader: rootLoader, 26 | }, 27 | { 28 | path: "pokemon/:pokemonId", 29 | element: , 30 | loader: pokemonDetailsLoader, 31 | }, 32 | ]); 33 | 34 | ReactDOM.createRoot(document.getElementById("root")).render( 35 | 36 | 37 | 38 | 39 | 40 | 41 | ); 42 | -------------------------------------------------------------------------------- /TallerReact/pokedex-app/src/routes/PokemonDetails.element.jsx: -------------------------------------------------------------------------------- 1 | import { useLoaderData } from "react-router-dom"; 2 | import Container from "@mui/material/Container"; 3 | import Typography from "@mui/material/Typography"; 4 | import Chip from "@mui/material/Chip"; 5 | import Header from "../components/Header"; 6 | import Table from "@mui/material/Table"; 7 | import TableBody from "@mui/material/TableBody"; 8 | import TableCell from "@mui/material/TableCell"; 9 | import TableContainer from "@mui/material/TableContainer"; 10 | import TableHead from "@mui/material/TableHead"; 11 | import TableRow from "@mui/material/TableRow"; 12 | import Paper from "@mui/material/Paper"; 13 | import Grid from "@mui/material/Grid"; 14 | import { capitalizeWord } from "../utils/capitalizeWord"; 15 | import { styled } from "@mui/material/styles"; 16 | import { ScrollRestoration } from "react-router-dom"; 17 | import ImgNotAvailable from "../assets/Image_not_available.png"; 18 | 19 | const ImgContainer = styled("div")` 20 | display: flex; 21 | justify-content: center; 22 | margin-bottom: 1rem; 23 | `; 24 | 25 | const Img = styled("img")` 26 | max-width: 100%; 27 | `; 28 | 29 | const ListItem = styled("li")(({ theme }) => ({ 30 | margin: theme.spacing(0.5), 31 | listStyle: "none", 32 | })); 33 | 34 | const List = styled("ul")` 35 | display: flex; 36 | flex-wrap: wrap; 37 | padding-left: 0; 38 | justify-content: center; 39 | `; 40 | 41 | const PokemonDetails = () => { 42 | const { pokemon } = useLoaderData(); 43 | return ( 44 | <> 45 | 46 |
47 | 48 | 49 | # {pokemon.id} 50 | 51 | 52 | {`${pokemon.name} 60 | 61 | 62 | 63 | 64 | Stats 65 | 66 | 67 | 68 | 69 | 70 | Stat 71 | Value 72 | 73 | 74 | 75 | {pokemon.stats.map((stat) => ( 76 | 80 | 81 | {capitalizeWord(stat.stat.name)} 82 | 83 | {stat.base_stat} 84 | 85 | ))} 86 | 87 |
88 |
89 |
90 | 91 | 92 | Types 93 | 94 | 95 | {pokemon.types.map((type) => ( 96 | 97 | 101 | 102 | ))} 103 | 104 | 105 | Abilities 106 | 107 | 108 | {pokemon.abilities.map((ability) => ( 109 | 110 | 114 | 115 | ))} 116 | 117 | 118 |
119 | 120 | Moves 121 | 122 | 123 | {pokemon.moves.map((move) => ( 124 | 125 | 130 | 131 | ))} 132 | 133 |
134 | 135 | ); 136 | }; 137 | 138 | export default PokemonDetails; 139 | -------------------------------------------------------------------------------- /TallerReact/pokedex-app/src/routes/PokemonDetails.loader.js: -------------------------------------------------------------------------------- 1 | import { getPokemon } from "../services/getPokemon"; 2 | 3 | export async function loader({ params }) { 4 | const pokemon = await getPokemon(params.pokemonId); 5 | return { pokemon }; 6 | } 7 | -------------------------------------------------------------------------------- /TallerReact/pokedex-app/src/routes/Root.element.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { Link, useLoaderData } from "react-router-dom"; 3 | import { ScrollRestoration } from "react-router-dom"; 4 | import InfiniteScroll from "react-infinite-scroll-component"; 5 | import Container from "@mui/material/Container"; 6 | import Grid from "@mui/material/Grid"; 7 | import { styled } from "@mui/material/styles"; 8 | import Header from "../components/Header"; 9 | import PokemonCard from "../components/PokemonCard"; 10 | import { capitalizeWord } from "../utils/capitalizeWord"; 11 | 12 | const CustomLink = styled(Link)` 13 | text-decoration: none; 14 | height: 100%; 15 | display: block; 16 | `; 17 | 18 | function Root() { 19 | const { pokemons, next } = useLoaderData(); 20 | 21 | const [pokemonList, setPokemonList] = useState(pokemons); 22 | const [nextPage, setNextPage] = useState(next); 23 | 24 | const fetchNextPage = async () => { 25 | const data = await fetch(next); 26 | const dataJson = await data.json(); 27 | setPokemonList((prev) => [...prev, ...dataJson.results]); 28 | setNextPage(dataJson.next); 29 | }; 30 | 31 | return ( 32 | <> 33 | 34 |
35 | 36 | fetchNextPage()} 39 | hasMore={!!nextPage} 40 | loader={

Loading...

} 41 | > 42 | 43 | {pokemonList.map((item, index) => ( 44 | 45 | 46 | 50 | 51 | 52 | ))} 53 | 54 |
55 |
56 | 57 | ); 58 | } 59 | 60 | export default Root; 61 | -------------------------------------------------------------------------------- /TallerReact/pokedex-app/src/routes/Root.loader.js: -------------------------------------------------------------------------------- 1 | import { getPokemonList } from "../services/getPokemonList"; 2 | 3 | export async function loader() { 4 | const data = await getPokemonList(50); 5 | return { pokemons: data.results, next: data.next }; 6 | } 7 | -------------------------------------------------------------------------------- /TallerReact/pokedex-app/src/services/getPokemon.js: -------------------------------------------------------------------------------- 1 | export const getPokemon = (pokemonId) => { 2 | return fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonId}`) 3 | .then((res) => res.json()) 4 | .then((data) => data); 5 | }; 6 | -------------------------------------------------------------------------------- /TallerReact/pokedex-app/src/services/getPokemonList.js: -------------------------------------------------------------------------------- 1 | export const getPokemonList = (limit = 151) => { 2 | return fetch(`https://pokeapi.co/api/v2/pokemon/?limit=${limit}`) 3 | .then((res) => res.json()) 4 | .then((data) => data); 5 | }; 6 | -------------------------------------------------------------------------------- /TallerReact/pokedex-app/src/utils/capitalizeWord.js: -------------------------------------------------------------------------------- 1 | export const capitalizeWord = (word) => { 2 | const firstLetterUpperCase = word.charAt(0).toUpperCase(); 3 | return `${firstLetterUpperCase}${word.slice(1)}`; 4 | }; 5 | -------------------------------------------------------------------------------- /TallerReact/pokedex-app/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /TallerVue/Escuela de Vue - Techschool v2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerVue/Escuela de Vue - Techschool v2.pdf -------------------------------------------------------------------------------- /TallerVue/README.md: -------------------------------------------------------------------------------- 1 | # Taller: Desarrollando un Registro de combates Pokémon! 2 | 3 | **Mentor de esta edición:** Sergio Azócar [(@sergioazoc)](https://www.sergioazocar.com) 4 | 5 | ## Descripción del Taller 6 | 7 | En este taller vas a desarrollar un registro de combates entre 2 Pokémons aleatorios, utilizando vue 3 y el api de PokeApi 8 | 9 | ## Objetivo del Taller 10 | 11 | La finalidad de este taller es que aprendas a utilizar Vue 3 con el Composition Api y aplicar buenas prácticas de desarrollo 12 | 13 | ## Prerrequisitos 14 | 15 | - Conocimientos en JavaScript/Vue. 16 | - Cuenta activa en GitHub. 17 | - Tener instalado Node.js v18 o superior y npm en tu laptop. 18 | - Laptop con un editor de texto. 19 | 20 | ## Material de apoyo 21 | 22 | Dentro de esta carpeta encontrarás archivos, guías y recursos que te serán de gran utilidad durante el taller. Te recomendamos descargar y revisar estos materiales con anticipación para aprovechar al máximo la sesión. 23 | 24 | --- 25 | 26 | Esperamos que aprendas, compartas y te diviertas creando este proyecto con Vue 3 <3 27 | 28 | Si tienes dudas o te gustaría comentar algo, abre un issue en este repo o contacta directo al Mentor de esta edición. 29 | -------------------------------------------------------------------------------- /TallerVue/poke-battle/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | module.exports = { 3 | root: true, 4 | 'extends': [ 5 | 'plugin:vue/vue3-recommended', 6 | 'eslint:recommended' 7 | ], 8 | parserOptions: { 9 | ecmaVersion: 'latest' 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /TallerVue/poke-battle/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist 13 | dist-ssr 14 | coverage 15 | *.local 16 | 17 | /cypress/videos/ 18 | /cypress/screenshots/ 19 | 20 | # Editor directories and files 21 | .vscode/* 22 | !.vscode/extensions.json 23 | .idea 24 | *.suo 25 | *.ntvs* 26 | *.njsproj 27 | *.sln 28 | *.sw? 29 | 30 | *.tsbuildinfo 31 | -------------------------------------------------------------------------------- /TallerVue/poke-battle/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "Vue.volar", 4 | "Vue.vscode-typescript-vue-plugin", 5 | "dbaeumer.vscode-eslint" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /TallerVue/poke-battle/README.md: -------------------------------------------------------------------------------- 1 | # poke-battle 2 | 3 | This template should help get you started developing with Vue 3 in Vite. 4 | 5 | ## Recommended IDE Setup 6 | 7 | [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin). 8 | 9 | ## Customize configuration 10 | 11 | See [Vite Configuration Reference](https://vitejs.dev/config/). 12 | 13 | ## Project Setup 14 | 15 | ```sh 16 | npm install 17 | ``` 18 | 19 | ### Compile and Hot-Reload for Development 20 | 21 | ```sh 22 | npm run dev 23 | ``` 24 | 25 | ### Compile and Minify for Production 26 | 27 | ```sh 28 | npm run build 29 | ``` 30 | 31 | ### Lint with [ESLint](https://eslint.org/) 32 | 33 | ```sh 34 | npm run lint 35 | ``` 36 | -------------------------------------------------------------------------------- /TallerVue/poke-battle/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Poke-Battle 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /TallerVue/poke-battle/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./src/*"] 5 | } 6 | }, 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /TallerVue/poke-battle/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "poke-battle", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview", 10 | "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore" 11 | }, 12 | "dependencies": { 13 | "axios": "^1.7.4", 14 | "vue": "^3.3.11" 15 | }, 16 | "devDependencies": { 17 | "@vitejs/plugin-vue": "^4.5.2", 18 | "eslint": "^8.49.0", 19 | "eslint-plugin-vue": "^9.17.0", 20 | "vite": "^5.4.12" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /TallerVue/poke-battle/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerVue/poke-battle/public/favicon.ico -------------------------------------------------------------------------------- /TallerVue/poke-battle/src/App.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /TallerVue/poke-battle/src/api/index.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | const api = axios.create({ 4 | baseURL: 'https://pokeapi.co/api/v2/', 5 | }) 6 | 7 | export default api -------------------------------------------------------------------------------- /TallerVue/poke-battle/src/assets/main.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSConfCL/techschool/62699ec69de5cb44b66c6a8abde01e52c77b8d4c/TallerVue/poke-battle/src/assets/main.css -------------------------------------------------------------------------------- /TallerVue/poke-battle/src/components/PokemonCard.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | -------------------------------------------------------------------------------- /TallerVue/poke-battle/src/composables/usePokemon.js: -------------------------------------------------------------------------------- 1 | // importar función desde los services que busca un Pokémon por ID 2 | import { } from '@/services/pokemon.services' 3 | 4 | const usePokemon = () => { 5 | 6 | // Crear funciones y lógica necesaria para retornar los datos que necesitaremos en la vista principal 7 | 8 | return { 9 | 10 | } 11 | } 12 | 13 | export default usePokemon -------------------------------------------------------------------------------- /TallerVue/poke-battle/src/main.js: -------------------------------------------------------------------------------- 1 | import './assets/main.css' 2 | 3 | import { createApp } from 'vue' 4 | import App from './App.vue' 5 | 6 | createApp(App).mount('#app') 7 | -------------------------------------------------------------------------------- /TallerVue/poke-battle/src/services/pokemon.services.js: -------------------------------------------------------------------------------- 1 | import api from "@/api" 2 | 3 | // crear una función que reciba el ID de un Pokémon y me devuelva los datos de ese Pokémon usando el api de PokeApi -------------------------------------------------------------------------------- /TallerVue/poke-battle/vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | plugins: [ 9 | vue(), 10 | ], 11 | resolve: { 12 | alias: { 13 | '@': fileURLToPath(new URL('./src', import.meta.url)) 14 | } 15 | } 16 | }) 17 | --------------------------------------------------------------------------------