diff --git a/README.md b/README.md index a45b7d5..2dcf4f0 100644 --- a/README.md +++ b/README.md @@ -4,620 +4,180 @@ * [1. Preámbulo](#1-preámbulo) * [2. Resumen del proyecto](#2-resumen-del-proyecto) -* [3. Objetivos de aprendizaje](#3-objetivos-de-aprendizaje) -* [4. Consideraciones generales](#4-consideraciones-generales) -* [5. Criterios de aceptación mínimos del proyecto](#5-criterios-de-aceptación-mínimos-del-proyecto) -* [6. Hacker edition](#6-hacker-edition) -* [7. Consideraciones técnicas](#7-consideraciones-técnicas) -* [8. Pistas, tips y lecturas complementarias](#8-pistas-tips-y-lecturas-complementarias) -* [9. Checklist](#9-checklist) +* [3. Historias de Usuarios y Diseño de la interfaz de usuario ](#3-objetivos-de-aprendizaje) +* [4. Implemententación de la interfaz de usuario.](#4-producto-final) +* [5. Pruebas unitarias.](#5-pruebas-unitarias) +* [6. Checklist.](#6-checklist) + *** ## 1. Preámbulo -Según [Forbes](https://www.forbes.com/sites/bernardmarr/2018/05/21/how-much-data-do-we-create-every-day-the-mind-blowing-stats-everyone-should-read), -el 90% de la data que existe hoy ha sido creada durante los últimos dos años. -Cada día generamos 2.5 millones de terabytes de datos, una cifra sin -precedentes. - -No obstante, los datos por sí mismos son de poca utilidad. Para que esas -grandes cantidades de datos se conviertan en **información** fácil de leer para -los usuarios, necesitamos entender y procesar estos datos. Una manera simple de -hacerlo es creando _interfaces_ y _visualizaciones_. - -En la siguiente imagen, podrás ver cómo con la data que que se ve en la parte -izquierda se puede construir una interfaz amigable y entendible por las -usuarias, al lado derecho. - -![pokemon-data-to-ui](https://user-images.githubusercontent.com/12631491/218505816-c6d11758-9de4-428f-affb-2a56ea4d68c4.png) - -## 2. Resumen del proyecto +Rick y Morty es una serie de televisión americana de animación para adultos creada por Justin Roiland y Dan Harmon en 2013 para Adult Swim, también se emitió en Cartoon Network. La serie sigue las desventuras de un científico, Rick Sanchez, y su fácilmente influenciable nieto, Morty, quienes pasan el tiempo entre la vida doméstica y los viajes espaciales, temporales e intergalácticos. Dan Harmon, el co-creador de la serie y Justin Roiland son los encargados de las voces principales de Morty y Rick, la serie también incluye las voces de Chris Parnell, Spencer Grammer y Sarah Chalke. -En este proyecto **construirás una _página web_ para visualizar un -_conjunto (set) de datos_** que se adecúe a lo que descubras que tu usuario -necesita. +![rickandmorty](./src/images/rickandmorty.webp) -Como entregable final tendrás una página web que permita **visualizar la data, -filtrarla, ordenarla y hacer algún cálculo agregado**. Con cálculo agregado -nos referimos a distintos cálculos que puedes hacer con la data para mostrar -información aún más relevante para los usuarios (promedio, el valor máximo -o mínimo, etc). +## 2. Definición del producto -Esta vez te proponemos una serie de datos de diferentes _temáticas_ para que -explores y decidas con qué temática te interesa trabajar. Hemos elegido -específicamente estos sets de datos porque creemos que se adecúan bien a esta -etapa de tu aprendizaje. +En este proyecto el objetivo principal es que el usuario de Rick and Morty Lovers pueda ver una interfaz con la data de la serie televisión, en donde pueda encontrar las características más importantes de sus personajes, buscar, filtrar y ordenar los mismos y también visualizar la estadística de personajes por género. -Una vez que definas tu área de interés, buscar entender quién es tu usuario -y qué necesita saber o ver exactamente; luego podrás construir la interfaz que -le ayude a interactuar y entender mejor esos datos. - -Estos son datos que te proponemos: - -* [Pokémon](src/data/pokemon/pokemon.json): - En este set encontrarás una lista con los 251 Pokémon de la región de Kanto - y Johto, junto con sus respectivas estadísticas usadas en el juego - [Pokémon GO](http://pokemongolive.com). - - [Investigación con jugadores de Pokémon Go](src/data/pokemon/README.md) - -* [League of Legends - Challenger leaderboard](src/data/lol/lol.json): - Este set de datos muestra la lista de campeones en una liga del - juego League of Legends (LoL). - - [Investigación con jugadores de LoL](src/data/lol/README.md) +Estos son los datos utilizados: * [Rick and Morty](src/data/rickandmorty/rickandmorty.json). Este set nos proporciona la lista de los personajes de la serie Rick and Morty. [API Rick and Morty](https://rickandmortyapi.com). - [Investigación con seguidores de Rick and Morty](src/data/rickandmorty/README.md) -* [Juegos Olímpicos de Río de Janeiro](src/data/athletes/athletes.json). - Este set nos proporciona la lista de los atletas que ganaron medallas en las - olímpiadas de Río de Janeiro. - - [Investigación con interesados en juegos olímpicos de Río de Janeiro](src/data/athletes/README.md) - -* [Studio Ghibli](src/data/ghibli/ghibli.json). - En este set encontrarás una lista de las animaciones y sus personajes del - [Studio Ghibli](https://ghiblicollection.com/). - - [Investigación con seguidores de las animaciones del Studio Ghibli](src/data/ghibli/README.md) - -* [Harry Potter](src/data/harrypotter/harry.json). - En este set encontrarás una lista de los personajes,libros pociones - y hechizos de toda la saga de - [Harry Potter](https://harrypotter.fandom.com). - - [Investigación con seguidoras de Harry Potter](src/data/harrypotter/README.md) - -El objetivo principal de este proyecto es que aprendas a diseñar y construir una -interfaz web donde se pueda visualizar y manipular data, entendiendo lo que el -usuario necesita. - -## 3. Objetivos de aprendizaje - -Reflexiona y luego marca los objetivos que has llegado a entender y aplicar en tu proyecto. Piensa en eso al decidir tu estrategia de trabajo. - -### HTML - -- [ ] **Uso de HTML semántico** - -
Links

- - * [HTML semántico](https://curriculum.laboratoria.la/es/topics/html/02-html5/02-semantic-html) - * [Semantics - MDN Web Docs Glossary](https://developer.mozilla.org/en-US/docs/Glossary/Semantics#Semantics_in_HTML) -

- -### CSS - -- [ ] **Uso de selectores de CSS** -
Links

+## 3. Historias de Usuario - * [Intro a CSS](https://curriculum.laboratoria.la/es/topics/css/01-css/01-intro-css) - * [CSS Selectors - MDN](https://developer.mozilla.org/es/docs/Web/CSS/CSS_Selectors) -

+*Historia Usuario 1:* -- [ ] **Modelo de caja (box model): borde, margen, padding** +Yo como usuario de Rick and Morty Lovers quiero ver los personajes para conocerlos. -
Links

- * [Box Model & Display](https://curriculum.laboratoria.la/es/topics/css/01-css/02-boxmodel-and-display) - * [The box model - MDN](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/The_box_model) - * [Introduction to the CSS box model - MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model) - * [CSS display - MDN](https://developer.mozilla.org/pt-BR/docs/Web/CSS/display) - * [display - CSS Tricks](https://css-tricks.com/almanac/properties/d/display/) -

- -- [ ] **Uso de flexbox en CSS** - -
Links

- - * [A Complete Guide to Flexbox - CSS Tricks](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) - * [Flexbox Froggy](https://flexboxfroggy.com/#es) - * [Flexbox - MDN](https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox) -

- -### Web APIs - -- [ ] **Uso de selectores del DOM** - -
Links

- - * [Manipulación del DOM](https://curriculum.laboratoria.la/es/topics/browser/02-dom/03-1-dom-methods-selection) - * [Introducción al DOM - MDN](https://developer.mozilla.org/es/docs/Web/API/Document_Object_Model/Introduction) - * [Localizando elementos DOM usando selectores - MDN](https://developer.mozilla.org/es/docs/Web/API/Document_object_model/Locating_DOM_elements_using_selectors) -

+#### Prototipo de baja fidelidad -- [ ] **Manejo de eventos del DOM (listeners, propagación, delegación)** +![Prototipo de baja fidelidad](./src/images/prototipo-baja-hu1.jpg) -
Links

- * [Introducción a eventos - MDN](https://developer.mozilla.org/es/docs/Learn/JavaScript/Building_blocks/Events) - * [EventTarget.addEventListener() - MDN](https://developer.mozilla.org/es/docs/Web/API/EventTarget/addEventListener) - * [EventTarget.removeEventListener() - MDN](https://developer.mozilla.org/es/docs/Web/API/EventTarget/removeEventListener) - * [El objeto Event](https://developer.mozilla.org/es/docs/Web/API/Event) -

+#### Prototipo de alta fidelidad -- [ ] **Manipulación dinámica del DOM** +![Prototipo de alta fidelidad](./src/images/figma-hu1.jpg) -
Links

+*Historia Usuario 2:* - * [Introducción al DOM](https://developer.mozilla.org/es/docs/Web/API/Document_Object_Model/Introduction) - * [Node.appendChild() - MDN](https://developer.mozilla.org/es/docs/Web/API/Node/appendChild) - * [Document.createElement() - MDN](https://developer.mozilla.org/es/docs/Web/API/Document/createElement) - * [Document.createTextNode()](https://developer.mozilla.org/es/docs/Web/API/Document/createTextNode) - * [Element.innerHTML - MDN](https://developer.mozilla.org/es/docs/Web/API/Element/innerHTML) - * [Node.textContent - MDN](https://developer.mozilla.org/es/docs/Web/API/Node/textContent) -

+Yo como usuario de Rick and Morty Lovers quiero buscar los personajes por su nombre para acceder de forma más especifica -### JavaScript -- [ ] **Diferenciar entre tipos de datos primitivos y no primitivos** +#### Prototipo de baja fidelidad -- [ ] **Arrays (arreglos)** +![Prototipo de baja fidelidad](./src/images/prototipo-baja-hu2.jpg) -
Links

- * [Arreglos](https://curriculum.laboratoria.la/es/topics/javascript/04-arrays) - * [Array - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/) - * [Array.prototype.sort() - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) - * [Array.prototype.forEach() - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) - * [Array.prototype.map() - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/map) - * [Array.prototype.filter() - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) - * [Array.prototype.reduce() - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) -

+#### Prototipo de alta fidelidad -- [ ] **Objetos (key, value)** +![Prototipo de alta fidelidad](./src/images/figma-hu2.jpg) -
Links

+*Historia Usuario 3:* - * [Objetos en JavaScript](https://curriculum.laboratoria.la/es/topics/javascript/05-objects/01-objects) -

+Yo como usuario de Rick and Morty Lovers quiero filtrar los personajes para acceder a información de especie y género de forma más especifica -- [ ] **Variables (declaración, asignación, ámbito)** -
Links

- * [Valores, tipos de datos y operadores](https://curriculum.laboratoria.la/es/topics/javascript/01-basics/01-values-variables-and-types) - * [Variables](https://curriculum.laboratoria.la/es/topics/javascript/01-basics/02-variables) -

+#### Prototipo de baja fidelidad -- [ ] **Uso de condicionales (if-else, switch, operador ternario, lógica booleana)** +![Prototipo de baja fidelidad](./src/images/prototipo-baja-hu3.jpg) -
Links

- * [Estructuras condicionales y repetitivas](https://curriculum.laboratoria.la/es/topics/javascript/02-flow-control/01-conditionals-and-loops) - * [Tomando decisiones en tu código — condicionales - MDN](https://developer.mozilla.org/es/docs/Learn/JavaScript/Building_blocks/conditionals) -

+#### Prototipo de alta fidelidad -- [ ] **Uso de bucles/ciclos (while, for, for..of)** +![Prototipo de alta fidelidad](./src/images/figma-hu3.jpg) -
Links

- * [Bucles (Loops)](https://curriculum.laboratoria.la/es/topics/javascript/02-flow-control/02-loops) - * [Bucles e iteración - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Guide/Loops_and_iteration) -

+*Historia Usuario 4:* -- [ ] **Funciones (params, args, return)** +Yo como usuario de Rick and Morty Lovers quiero ordenar los personajes para encontrarlos en orden alfabético. -
Links

- * [Funciones (control de flujo)](https://curriculum.laboratoria.la/es/topics/javascript/02-flow-control/03-functions) - * [Funciones clásicas](https://curriculum.laboratoria.la/es/topics/javascript/03-functions/01-classic) - * [Arrow Functions](https://curriculum.laboratoria.la/es/topics/javascript/03-functions/02-arrow) - * [Funciones — bloques de código reutilizables - MDN](https://developer.mozilla.org/es/docs/Learn/JavaScript/Building_blocks/Functions) -

+#### Prototipo de baja fidelidad -- [ ] **Pruebas unitarias (unit tests)** +![Prototipo de baja fidelidad](./src/images/prototipo-baja-hu4.jpg) -
Links

- * [Empezando con Jest - Documentación oficial](https://jestjs.io/docs/es-ES/getting-started) -

+#### Prototipo de alta fidelidad -- [ ] **Módulos de ECMAScript (ES Modules)** +![Prototipo de alta fidelidad](./src/images/figma-hu4.jpg) -
Links

+*Historia Usuario 5:* - * [import - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Statements/import) - * [export - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Statements/export) -

+Yo como usuario de Rick and Morty Lovers quiero ver estadísticas sobre los personajes para conocer la cantidad por especia que hay en la serie. -- [ ] **Uso de linter (ESLINT)** -- [ ] **Uso de identificadores descriptivos (Nomenclatura y Semántica)** +#### Prototipo de baja fidelidad -- [ ] **Diferenciar entre expresiones (expressions) y sentencias (statements)** +![Prototipo de baja fidelidad](./src/images/prototipo-baja-hu5.jpg) -### Control de Versiones (Git y GitHub) -- [ ] **Git: Instalación y configuración** +#### Prototipo de alta fidelidad -- [ ] **Git: Control de versiones con git (init, clone, add, commit, status, push, pull, remote)** +![Prototipo de alta fidelidad](./src/images/figma-hu5.jpg) -- [ ] **Git: Integración de cambios entre ramas (branch, checkout, fetch, merge, reset, rebase, tag)** +*Link a Figma:* +![Link a Figma](https://www.figma.com/file/TqvwtLuqPk3W6o0ut0DZ1C/Rick-and-Morty-Lovers?node-id=0-1&t=wesxInzlX0jsB2ga-0) -- [ ] **GitHub: Creación de cuenta y repos, configuración de llaves SSH** -- [ ] **GitHub: Despliegue con GitHub Pages** +## 4. Implemententación de la interfaz de usuario. +#### Producto final -
Links

- * [Sitio oficial de GitHub Pages](https://pages.github.com/) -

+*Inicio* -- [ ] **GitHub: Colaboración en Github (branches | forks | pull requests | code review | tags)** +Al ingresar al inicio (home), carga los primeros 20 personajes de la data, y el usuario puede visualizar las opciones para filtrar, bien sea por nombre (en el buscador), por especie o por género, asímismo se encuentra un botón para ordenar alfabeticamente de forma ascendente y descendente. -### Centrado en el usuario +![Inicio](./src/images/home.png) -- [ ] **Diseñar y desarrollar un producto o servicio poniendo a las usuarias en el centro** +*Personajes* -### Diseño de producto +Al ingresar a la pestaña de personajes (characters), carga los 493 personajes que existen en la data, para que el usuario pueda acceder a la información de cada uno de ellos. -- [ ] **Crear prototipos de alta fidelidad que incluyan interacciones** +![Personajes](./src/images/characters.png) -- [ ] **Seguir los principios básicos de diseño visual** -### Investigación +*Interacción de las tarjetas* -- [ ] **Planear y ejecutar testeos de usabilidad de prototipos en distintos niveles de fidelidad** +Cada tarjeta de cada personaje, contiene en la parte trasera información relevante del mismo, con sólo dar clic el usuario puede acceder a esa información. -
Links

+![Interacción](./src/images/flip.png) - * [Intro a testeos usabilidad](https://coda.io/@bootcamp-laboratoria/contenido-ux/test-de-usabilidad-15) - * [Pruebas con Usuarios 1 — ¿Qué, cuándo y para qué testeamos?](https://eugeniacasabona.medium.com/pruebas-con-usuarios-1-qu%C3%A9-cu%C3%A1ndo-y-para-qu%C3%A9-testeamos-7c3a89b4b5e7) -

-## 4. Consideraciones generales +*Filtrar* -* Este proyecto se debe resolver en duplas. -* El rango de tiempo estimado para completar el proyecto es de 3 a 4 Sprints. -* El proyecto será entregado subiendo tu código a GitHub (commit/push) y la - interfaz será desplegada usando [GitHub Pages](https://pages.github.com/). +En la pantalla principal el usuario puede ver dos botones para filtrar los personajes, bien sea por especie o por género, y en la parte superior derecha un buscador que funciona con el nombre de los personajes; al escoger la opción que desee, le muestra todos los personajes que hay en la data con ese tipo de filtro (estos filtros funcionan de forma anidada). -## 5. Criterios de aceptación mínimos del proyecto +![Filtrar](./src/images/filter.png) -Los criterios para considerar que has completado este proyecto son: +*Ordenar* -### Definición del producto +Asímismo, se encuentra en la pantalla principal un botón para ordenar alfabéticamente de forma ascendente y descendente todos los personajes. -Documenta brevemente tu trabajo en el archivo `README.md` de tu repositorio, -contándonos cómo fue tu proceso de diseño y cómo crees que el producto resuelve -el problema (o problemas) que tiene tu usuario. +![Filtrado](./src/images/order.png) -### Historias de usuario +*Estadística* -Una vez que entiendas las necesidades de tus usuarios, escribe las [Historias -de Usuario](https://es.wikipedia.org/wiki/Historias_de_usuario) que representen -todo lo que el usuario necesita hacer/ver. Las **Historias de Usuario** deben -ser el resultado de tu proceso de investigación o _research_ de tus usuarios. +Al ingresar a la pestaña de estadísticas (stadistics), ubicada en la parte superior izquierda, el usuario podrá visualizar la estadística de los personajes por género. -Asegúrate de incluir la definición de terminado (_definition of done_) y los -Criterios de Aceptación para cada una. +![Filtrado](./src/images/statistics.png) -En la medida de lo posible, termina una historia de usuario antes de pasar -a la siguiente (Cumple con Definición de Terminado + Criterios de Aceptación). -### Diseño de la Interfaz de Usuario +## 5. Pruebas unitarias. +#### Test +![Test](./src/images/test.jpg) -#### Prototipo de baja fidelidad +#### Test de usabilidad: -Durante tu trabajo deberás haber hecho e iterado bocetos (_sketches_) de tu -solución usando papel y lápiz. Te recomendamos tomar fotos de todas las -iteraciones que hagas, que las subas a tu repositorio y las menciones en tu -`README.md`. +- Limitamos el mostrar todos los personajes, indicaron que se veía recargado. +- Mostramos los personajes en filas de 4 tarjetas y con cierto espacio entre ellos, para visualizarlos mejor. +- Aumentamos el tamaño de los botones de selección. +- Utilizamos una etiqueta para describir el nombre de cada botón de selección, para ser más descriptivo. +- Cambiamos el color de fondo de las opciones del botón de filtrado, para tener mejor contraste. +- Se realizó el anidado de los filtros buscar, especie y género, para que el usuario pueda encontrar el personaje de forma más específica. +- Agregamos interacción al link de estadística para desplegar una pantalla con la información del porcentaje por género. -#### Prototipo de alta fidelidad +## 6. Checklist. -Lo siguiente es diseñar tu Interfaz de Usuario (UI por sus siglas en inglés - -_User Interface_). Para eso debes aprender a utilizar alguna herramienta de -diseño visual. Nosotros te recomendamos [Figma](https://www.figma.com/) que es -una herramienta que funciona en el navegador y, además, puedes crear una cuenta -gratis. Sin embargo, eres libre de utilizar otros editores gráficos como -Illustrator, Photoshop, PowerPoint, Keynote, etc. - -El diseño debe representar el _ideal_ de tu solución. Digamos que es lo que -desearías implementar si tuvieras tiempo ilimitado para trabajar. Además, tu -diseño debe seguir los fundamentos de _visual design_. - -#### Testeos de usabilidad - -Durante el reto deberás hacer _tests_ de usabilidad con distintos usuarios, y -en base a los resultados, deberás iterar tus diseños. Cuéntanos -qué problemas de usabilidad detectaste a través de los _tests_ y cómo los -mejoraste en tu propuesta final. - -### Implementación de la Interfaz de Usuario (HTML/CSS/JS) - -Luego de diseñar tu interfaz de usuario deberás trabajar en su implementación. -**No** es necesario que construyas la interfaz exactamente como la diseñaste. -Tu tiempo de hacking es escaso, así que deberás priorizar - -Como mínimo, tu implementación debe: - -1. Mostrar la data en una interfaz: puede ser un card, una tabla, una lista, - etc. -2. Permitir al usuario interactuar para obtener la infomación que necesita. -3. Ser _responsive_, es decir, debe visualizarse sin problemas desde distintos - tamaños de pantallas: móviles, tablets y desktops. -4. Que la interfaz siga los fundamentos de _visual design_. - -### Pruebas unitarias - -El _boilerplate_ de este proyecto no incluye Pruebas Unitarias (_tests_), así es -que tendrás que escribirlas tú para las funciones encargadas de _procesar_, -_filtrar_ y _ordenar_ la data, así como _calcular_ estadísticas. - -Tus _pruebas unitarias_ deben dar una cobertura del 70% de _statements_ -(_sentencias_), _functions_ (_funciones_), _lines_ (_líneas_), y _branches_ -(_ramas_) del archivo `src/data.js` que contenga tus funciones y está detallado -en la sección de [Consideraciones técnicas](#srcdatajs). - -## 6. Hacker edition - -Las secciones llamadas _Hacker Edition_ son **opcionales**. Si **terminaste** -con todo lo anterior y te queda tiempo, intenta completarlas. Así podrás -profundizar y/o ejercitar más sobre los objetivos de aprendizaje del proyecto. - -Features/características extra sugeridas: - -* En lugar de consumir la data estática brindada en este repositorio, puedes - consumir la data de forma dinámica, cargando un archivo JSON por medio de - `fetch`. La carpeta `src/data` contiene una versión `.js` y una `.json` de - de cada set datos. -* Agregarle a tu interfaz de usuario implementada visualizaciones gráficas. Para - ello te recomendamos explorar librerías de gráficas como - [Chart.js](https://www.chartjs.org/) - o [Google Charts](https://developers.google.com/chart/). -* 100% Coverage - -## 7. Consideraciones técnicas - -La lógica del proyecto debe estar implementada completamente en JavaScript -(ES6), HTML y CSS. En este proyecto NO está permitido usar librerías o -frameworks, solo [vanilla JavaScript](https://medium.com/laboratoria-how-to/vanillajs-vs-jquery-31e623bbd46e), -con la excepción de librerías para hacer gráficas (charts); ver -[_Parte opcional_](#6-hacker-edition) más arriba. - -El _boilerplate_ contiene una estructura de archivos como punto de partida así -como toda la configuración de dependencias: - -```text -. -├── EXTRA.md -├── README.md -├── package.json -├── src -| ├── data (según con qué data trabajes) -| | ├── lol -| | | ├── lol.js -| | | ├── lol.json -| | | └── README.md -| | ├── pokemon -| | | ├── pokemon.js -| | | ├── pokemon.json -| | | └── README.md -| | └── rickandmorty -| | | ├── rickandmorty.js -| | | ├── rickandmorty.json -| | | └── README.md -| | └── athletes -| | | ├── athletes.js -| | | ├── athletes.json -| | | └── README.md -| | └── ghibli -| | | ├── ghibli.js -| | | ├── ghibli.json -| | | └── README.md -| ├── data.js -| ├── index.html -| ├── main.js -| └── style.css -└── test - └── data.spec.js - -directory: 7 file: 20 -``` - -### `src/index.html` - -Como en el proyecto anterior, existe un archivo `index.html`. Como ya sabes, -acá va la página que se mostrará al usuario. También nos sirve para indicar -qué scripts se usarán y unir todo lo que hemos hecho. - -### `src/main.js` - -Recomendamos usar `src/main.js` para todo tu código que tenga que ver con -mostrar los datos en la pantalla. Con esto nos referimos básicamente a la -interacción con el DOM. Operaciones como creación de nodos, registro de -manejadores de eventos (_event listeners_ o _event handlers_), .... - -Esta no es la única forma de dividir tu código, puedes usar más archivos y -carpetas, siempre y cuando la estructura sea clara para tus compañeras. - -En este archivo encontrarás una serie de _imports_ _comentados_. Para _cargar_ -las diferentes fuentes de datos tendrás que _descomentar_ la línea -correspondiente. - -Por ejemplo, si "descomentamos" la siguiente línea: - -```js -// import data from './data/lol/lol.js'; -``` - -La línea quedaría así: - -```js -import data from './data/lol/lol.js'; -``` - -Y ahora tendríamos la variable `data` disponible en el script `src/main.js`. - -### `src/data.js` - -El corazón de este proyecto es la manipulación de datos a través de arreglos -y objetos. - -Te recomendamos que este archivo contenga toda la funcionalidad que corresponda -a obtener, procesar y manipular datos (tus funciones). Por ejemplo: - -* `filterData(data, condition)`: esta función `filter` o filtrar recibiría la - data, y nos retornaría aquellos datos que sí cumplan con la condición. - -* `sortData(data, sortBy, sortOrder)`: esta función `sort` u ordenar - recibe tres parámetros. - El primer parámetro, `data`, nos entrega los datos. - El segundo parámetro, `sortBy`, nos dice con respecto a cuál de los campos de - la data se quiere ordenar. - El tercer parámetro, `sortOrder`, indica si se quiere ordenar de manera - ascendente o descendente. - -* `computeStats(data)`: la función `compute` o calcular, nos permitirá hacer - cálculos estadísticos básicos para ser mostrados de acuerdo a la data - proporcionada. - -Estos nombres de funciones y de parámetros son solamente referenciales, lo que -decidas depende de tu propia implementación. - -Estas funciones deben ser [_puras_](https://medium.com/laboratoria-developers/introducci%C3%B3n-a-la-programaci%C3%B3n-funcional-en-javascript-parte-2-funciones-puras-b99e08c2895d) -e independientes del DOM. Estas funciones serán después usadas desde el archivo -`src/main.js`, al cargar la página, y cada vez que el usuario interactúe (click, -filtrado, ordenado, ...). - -### `src/data` - -En esta carpeta están los datos de las diferentes fuentes. Encontrarás una -carpeta por cada fuente, y dentro de cada carpeta dos archivos: uno con la -extensión `.js` y otro `.json`. Ambos archivos contienen la misma data; la -diferencia es que el `.js` lo usaremos a través de una etiqueta ` +
+ +
+ +
+ + + +
+
+ + +
+ +
+ + +
+ +
+ + +
+
+ +
+ +
+ +
+
+
+ +
+
+
+ + + +
+ + + + + + + - + + \ No newline at end of file diff --git a/src/main.js b/src/main.js index 71c59f2..3321790 100644 --- a/src/main.js +++ b/src/main.js @@ -1,6 +1,227 @@ -import { example } from './data.js'; -// import data from './data/lol/lol.js'; -import data from './data/pokemon/pokemon.js'; -// import data from './data/rickandmorty/rickandmorty.js'; +import data from './data/rickandmorty/rickandmorty.js'; +import {searchByName, + filterGeneral, + filterByGender, + filterByOrderAZ, + filterByOrderZA, + calculate +} from './data.js'; -console.log(example, data); +//DECLARING VARIABLES +const characters = data.results; +const cutCharacters = characters.slice(0,20); + +const contentMain = document.getElementById('container-cards'); +const showCharacters = document.getElementById('showCharacters'); + +const searchInput = document.querySelector('#search'); +const selectSpecies = document.querySelector('#select-species'); +const selectGender = document.querySelector('#select-gender'); +const selectOrder = document.getElementById('select-order'); + +const modal = document.querySelector('.modal'); +const boxStatictics = document.querySelector('#box-statistics'); +const openModal = document.querySelector('#statistics'); +const closeModal = document.querySelector('.modal_close'); + + +// RENDERING THE DATA +document.addEventListener('DOMContentLoaded',()=>{ + show(cutCharacters); +}) + +showCharacters.addEventListener('click', (e)=> { + e.preventDefault(); + show(characters); +}); + + +// SHOWING ALL CHARACTERS +function show(characters) { + + contentMain.innerHTML = ''; + + characters.forEach(element => { + const contentCards = document.createElement('div');// div card front y revers. + + const divCard = document.createElement('div'); + const imag = document.createElement('img'); + const nameCharacters = document.createElement('h2'); + + contentCards.classList.add('content-front-reverse') + divCard.classList.add('cards-front'); + imag.classList.add('img'); + nameCharacters.classList.add('text-name-f'); + + nameCharacters.textContent = element.name; + imag.src = element.image; + + divCard.appendChild(imag); + divCard.appendChild(nameCharacters); + + const divCard2 = document.createElement('div'); + const nameCharacters2 = document.createElement('h2'); + const paragraph = document.createElement('p'); + const paragraph2 = document.createElement('p'); + const paragraph3 = document.createElement('p'); + const paragraph4 = document.createElement('p'); + + divCard2.classList.add('cards-reverse'); + nameCharacters2.classList.add('text-name-r'); + paragraph.classList.add('text1'); + paragraph2.classList.add('text1'); + paragraph3.classList.add('text1'); + paragraph4.classList.add('text1'); + + nameCharacters2.textContent = element.name; + paragraph.textContent = 'Species: ' + element.species; + paragraph2.textContent = 'Gender: ' + element.gender; + paragraph3.textContent = 'Origin: ' + element['origin']['name']; + paragraph4.textContent = 'Location: ' + element['location']['name']; + + divCard2.appendChild(nameCharacters2); + divCard2.appendChild(paragraph); + divCard2.appendChild(paragraph2); + divCard2.appendChild(paragraph3); + divCard2.appendChild(paragraph4); + + contentCards.appendChild(divCard); + contentCards.appendChild(divCard2); + contentMain.appendChild(contentCards); + + contentCards.addEventListener('click',()=>{ + contentCards.classList.toggle('active'); + }) + }) +} + + +// FILTERING CHARACTERS +let searchValue = ''; +let specieValue = ''; +let genderValue = ''; + +// SEARCH +searchInput.addEventListener('keyup',() => { + searchValue = searchInput.value.toLowerCase().trim(); + applyFilter(); +}); + + +// SPECIES +selectSpecies.addEventListener('change',(event) => { + specieValue = event.target.value; + applyFilter(); +}); + +// GENDER +selectGender.addEventListener('change',(event) => { + genderValue = event.target.value; + applyFilter(); +}); + + +//APPLY FILTER +function applyFilter() { + + const filterByName = searchValue === '' ? characters : searchByName(characters,searchValue); + const selectBySpecies =specieValue === '' ? filterByName : filterGeneral(filterByName,'species',specieValue); + const selectByGender = genderValue === '' ? selectBySpecies : filterGeneral(selectBySpecies,'gender',genderValue); + + if (selectByGender.length) { + show(selectByGender); + } else { + notFound(); + } +} + +// ALERT NOT FOUND +function notFound() { + contentMain.innerHTML = ''; + const messageError = document.createElement('h3'); + messageError.classList.add('messageError'); + messageError.textContent =`No result found for...'${searchInput.value}'`; + contentMain.appendChild(messageError); +} + +// ORDER A-Z / Z-A +selectOrder.addEventListener('change',() => { + const orderValue = selectOrder.options[selectOrder.selectedIndex].value; + + if (orderValue === 'Ascending') { + const orderAZ = filterByOrderAZ(characters,orderValue); + show(orderAZ); + } + + if (orderValue === 'Descending') { + const orderZA = filterByOrderZA(characters,orderValue); + show(orderZA); + } + +}); + +// PERCENTAGE event and function +openModal.addEventListener('click', (e)=> { + e.preventDefault(); + modal.classList.add('modal--show'); + showStat(); +}); + +closeModal.addEventListener('click', (e)=> { + e.preventDefault(); + + modal.classList.remove('modal--show'); +}); + + +function showStat () { + // Crear el subtítulo,clase y contenido + const subtitle = document.createElement('h2'); + subtitle.classList.add('modal-subtitle'); + subtitle.textContent = 'Character stats by gender'; + + boxStatictics.innerHTML = ''; + // Agregarlo al div "box-statistics" + boxStatictics.appendChild(subtitle); + + const percenFemale = calculate(filterByGender(characters,'Female'),characters); + const percenMale = calculate(filterByGender(characters,'Male'),characters); + const percenUnknown = calculate(filterByGender(characters,'unknown'),characters); + const percenGenderless = calculate(filterByGender(characters,'Genderless'),characters); + + // const subtitleStatics = document.createElement('p') + + const textStatictics1 = document.createElement('p'); + const textStatictics2 = document.createElement('p'); + const textStatictics3 = document.createElement('p'); + const textStatictics4 = document.createElement('p'); + const boxStatictics2 = document.createElement('div'); + + boxStatictics.classList.add('box-statis'); + boxStatictics2.classList.add('contain-text'); + + textStatictics1.classList.add('text-box'); + textStatictics2.classList.add('text-box'); + textStatictics3.classList.add('text-box'); + textStatictics4.classList.add('text-box'); + + textStatictics1.textContent = `In the series there are: ${percenFemale}% Female Characters`; + textStatictics2.textContent = `In the series there are: ${percenMale}% Male Characters`; + textStatictics3.textContent = `In the series there are: ${percenUnknown}% Unknown Characters`; + textStatictics4.textContent = `In the series there are: ${percenGenderless}% Genderless Characters`; + + boxStatictics2.appendChild(textStatictics1); + boxStatictics2.appendChild(textStatictics2); + boxStatictics2.appendChild(textStatictics3); + boxStatictics2.appendChild(textStatictics4); + boxStatictics.appendChild(boxStatictics2); +} + + +// GETTING DATA FROM JSON + +// fetch("./data/rickandmorty/rickandmorty.json") +// .then((resp) => resp.json()) +// .then((data) => { +// console.log(data); +// }) \ No newline at end of file diff --git a/src/style.css b/src/style.css index e69de29..b50ba42 100644 --- a/src/style.css +++ b/src/style.css @@ -0,0 +1,435 @@ +*{ + padding: 0; + margin: 0; + box-sizing: border-box; +} + +html{ + min-height: 100%; + position: relative; + font-size: 62.5%; +} + +body{ + margin-bottom: 120px; + background-image: url('images/fondo4.png'); +} + +.container{ + width: 90%; + max-width: 1500px; + margin: 0 auto; +} + + +/* ----------------------header--------------------------------- */ + +.content-nav{ + border-bottom: 1px solid #8181815f; + background-color:#07060675; +} + +.nav{ + display: flex; + flex-wrap: wrap; + gap: 20px; + justify-content: center; + align-items: center; + padding: 16px 0; +} + +.link{ + display: flex; + gap: 60px; +} + +.link li{ + list-style: none; +} + +.items{ + text-decoration: none; + font-size: 2rem; + color: #fff; +} + +.items:hover{ + transition: 0.3s ease; + color: #3ab54aae; +} + +.content-inp-icon{ + width: 100%; + max-width: 300px; + position: relative; +} + +.inp{ + display: block; + width: 100%; + padding: 7px ; + border-radius:8px; + outline: none; + border: 1px solid #615959; + border-radius: 13px; + background-color: white; +} + +.icon{ + width: 18px; + height: 24px; + position: absolute; + transform: translate(-50%, -50%); + left: 94%; + top: 50%; +} + +.logo{ + width: 100%; + max-width: 450px; + display: block; + margin: 0 auto; + padding: 30px; +} + +.content-select-all{ + margin: 0 auto; + padding: 15px 0 40px 0; + display: flex; + justify-content: center; + flex-wrap: wrap; + gap: 20px; +} + +.group-select{ + display: flex; + justify-content: center; + align-items: center; + margin-left: 20px; + gap: 10px; +} + +.label{ + color: white; + width: 60px; + font-size: 1.5rem; + font-weight: bold; +} + +.select{ + border-radius: 15px; + padding: 8px; + width: 120px; + background-color: #3ab54aae; + color: #fff; +} + +option{ + background-color: #0c232dc8; +} + +/* ----------------main--------------------------------------- */ + +.container-cards{ + display: flex; + justify-content: center; + align-items: center; + flex-wrap: wrap; + gap: 35px; + padding: 10px; +} + +.characters{ + display: flex; + justify-content: center; + align-items: center; + flex-wrap: wrap; + gap: 35px; + padding: 10px; +} + +/* CREATED FROM JS */ +.content-front-reverse{ + display: flex; + justify-content: center; + flex-wrap: wrap; + position: relative; + transform-style: preserve-3d; + transform: rotateY(0deg); + transition: .3s ease all; + border-radius: 9px; +} + +.cards-front, .cards-reverse{ + width: 80%; + height: 290px; + padding:0 0 10px 0; + border-radius: 9px; + border: 2px solid #3ab54aae; + background-color: #000; +} + +.img{ + width: 100%; + border-radius: 5px 5px 0 0; +} + +.text-name-f{ + font-size: 2rem; + text-align: center; + margin-top: 8px; + color: #fff; +} + +.cards-reverse{ + position: absolute; + top: 0; + transform: rotateY(180deg); + backface-visibility: hidden; + text-align: center; + padding-top: 60px; + background-color: #000; +} + +.content-front-reverse.active{ + transform: rotateY(180deg); +} + +.cards-front:hover{ + background-color: #3ab54a36; +} + +.text-name-r , .text1{ + color: #fff; + font-size: 2rem; + line-height: 25px; +} + +.messageError{ + font-size: 3rem; + font-weight: bold; + color: #fff; + padding-top: 100px; +} + +/* --------------------- modal------------------------------- */ + +.modal { + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #111111d4; + display: flex; + justify-content:center; + align-items: center; + opacity: 0; + pointer-events: none; + transition: opacity .6s; +} + +.modal--show { + opacity: 1; + pointer-events: unset; + transition: opacity .3s; +} + + .modal_container{ + width: 92%; + max-width: 550px; + margin: 0 auto; + position: relative; + } + +.modal-subtitle{ + font-size:2.5rem; + color: #000; + font-weight: bold; +} + +.box-statis{ + width: 100%; + max-width: 600px; + background-color: #e6dfdf; + opacity: 0.95; + height: 370px; + border-radius: 15px; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + gap: 20px; +} + +.text-box{ + font-size: 1.5rem; + text-align: center; + margin-top: 18px; + color: #111; + font-weight: bold; +} + +.modal_close{ + text-decoration: none; + background-color: #3ab54aef; + border-radius: 50px; + padding: 12px; + transition: background-color .3s; + position: absolute; + top: 0; + right:0; + transform: translate(40%, -40%); +} + +.modal_close img{ + width: 22px; +} + +.modal_close:hover { + color: black; + background-color:white; +} + +/* --------------------- footer------------------------------- */ + +.footer{ + position: absolute; + bottom: 0; + width: 100%; + padding: 10px 0; + color: #000; + background-color:#07060675; + border-top: 1px solid #8181815f; +} + +.content-footer{ + display: flex; + justify-content: center; + gap: 60px; +} + +.sofy, .andre{ + display: flex; + justify-content: center; + align-items: center; +} + +.logoGitHub{ + width: 60px; +} + +.link-github{ + text-decoration: none; + color: #fff; + font-size: 2rem; + font-weight: bold; +} + +span{ + padding: 7px; + border-bottom: 1px solid transparent; +} + +span:hover{ + border-bottom: 1px solid #fff; +} + +/* ---------------------------------------------------------- */ + +@media ( min-width:750px) { + .nav{ + justify-content: space-between; + } + .cards-front, .cards-reverse{ + width: 250px; + } + .search{ + width: 20px; + position: absolute; + left: 95%; + top: 50%; + transform: translate(-50%,-50%); + } + .text-box{ + font-size: 2rem; + } +} + + +@media (min-width:1050px){ + .cards-front, .cards-reverse{ + width: 240px; + } + .container{ + max-width: 1100px; + } + .content{ + max-width: 1200px; + margin: 0 auto; + } + .content-select-all{ + display: flex; + flex-wrap: nowrap; + max-width: 250px + } + .content-inp-icon{ + max-width: 400px; + } + .text-box{ + font-size: 2rem; + } +} + + +@media ( min-width:1900px) { + .nav{ + padding: 30px 0; + } + .container{ + max-width: 1900px; + } + .inp { + padding: 10px ; + } + .items{ + font-size: 2.5rem; + font-weight: bold; + } + .logo{ + margin-top: 50px; + } + .content-select-all{ + margin-top: 50px; + } + .label{ + font-size: 2rem; + width: 80px; + } + .select { + width: 150px; + height: 40px; + font-size: 18px; + } + .content { + max-width: 1500px; + margin: 0 auto; + } + .container-cards{ + gap: 60px; + margin-top: 80px; + } + .cards-front, .cards-reverse{ + width: 300px; + height: 350px; + } + .text-name-r , .text1 { + font-size: 2.5rem; + padding: 2px; + } + .text-box{ + font-size: 2rem; + } +} \ No newline at end of file diff --git a/test/data.spec.js b/test/data.spec.js index 09b1f23..c779d21 100644 --- a/test/data.spec.js +++ b/test/data.spec.js @@ -1,23 +1,148 @@ -import { example, anotherExample } from '../src/data.js'; +import { searchByName, + filterGeneral, + filterByGender, + filterByOrderAZ, + filterByOrderZA, + calculate +} from '../src/data.js'; +// FILTER BY NAME -describe('example', () => { - it('is a function', () => { - expect(typeof example).toBe('function'); +describe('searchByName', () => { + it('Debería ser una función', () => { + expect(typeof searchByName).toBe('function'); }); - it('returns `example`', () => { - expect(example()).toBe('example'); + it ('debería devolver un array vacío si el resultado no coincide', () => { + const characters = [ + { name: 'Rick Sanchez', species: 'Human' }, + { name: 'Morty Smith', species: 'Human' } + ]; + + const results = searchByName(characters,'Beth'); + expect (results).toEqual([]); + }); + + it ('debería devolver el personaje que el usuario está buscando', () => { + const characters = [ + { name: 'Rick Sanchez', species: 'Human'}, + { name: 'Morty Smith', species: 'Human' } + ]; + + const results = searchByName(characters,'rick'); + expect (results).toEqual([{ name: 'Rick Sanchez', species: 'Human' }]); + }); + + it ('debería poder buscar sin importar si el usuario ingresa mayúsculas o minúsculas', () => { + const characters = [ + { name: 'Rick Sanchez', species: 'Human'}, + { name: 'Morty Smith', species: 'Human' } + ]; + + const results = searchByName(characters,'RICK'); + expect (results).toEqual([{ name: 'Rick Sanchez', species: 'Human' }]); + }); +}); + + +// FILTER GENERAL + +describe('filterGeneral', () => { + it('Debería ser una función', () => { + expect(typeof filterGeneral).toBe('function'); + }); + + it ('debería devolver todos los robots cuando el usuario seleccione la opción robots', () => { + const characters = [ + { name: 'Rick Sanchez', species: 'Human'}, + { name: 'Morty Smith', species: 'Human' }, + {name: 'Conroy', species: "Robot"}, + ]; + + const results = filterGeneral(characters, 'species','Robot'); + expect (results).toEqual([{name: 'Conroy', species: "Robot"}]); }); }); +// FILTER BY GENDER -describe('anotherExample', () => { - it('is a function', () => { - expect(typeof anotherExample).toBe('function'); +describe('filterByGender', () => { + it('Debería ser una función', () => { + expect(typeof filterByGender).toBe('function'); }); - it('returns `anotherExample`', () => { - expect(anotherExample()).toBe('OMG'); + it ('debería devolver todos los personajes femeninos cuando el usuario seleccione la opción femenino', () => { + const characters = [ + { name: 'Rick Sanchez', gender: 'Male'}, + { name: 'Morty Smith', gender: 'Male' }, + { name: 'Creepy Little Girl', gender: 'Female'}, + { name: 'Cynthia', gender: 'Female'} + ]; + + const results = filterByGender(characters,'Female'); + expect (results).toEqual([ {name: 'Creepy Little Girl', gender: 'Female'},{name: 'Cynthia', gender: 'Female'}]); }); }); + +// ORDER ASCENDING + +describe('filterByOrderAZ', () => { + it('Debería ser una función', () => { + expect(typeof filterByOrderAZ).toBe('function'); + }); + + it ('debería devolver todos los personajes ordenados alfabéticamente de formas ascendente', () => { + const characters = [ + { name: 'Rick Sanchez', gender: 'Male'}, + { name: 'Morty Smith', gender: 'Male' }, + { name: 'Creepy Little Girl', gender: 'Female'}, + { name: 'Cynthia', gender: 'Female'} + ]; + + const results = filterByOrderAZ(characters); + expect (results).toEqual([ {name: 'Creepy Little Girl', gender: 'Female'},{name: 'Cynthia', gender: 'Female'},{ name: 'Morty Smith', gender: 'Male' },{ name: 'Rick Sanchez', gender: 'Male'} ]); + }); +}); + +// ORDER DESCENDING + +describe('filterByOrderZA', () => { + it('Debería ser una función', () => { + expect(typeof filterByOrderZA).toBe('function'); + }); + + it ('debería devolver todos los personajes ordenados alfabéticamente de formas ascendente', () => { + const characters = [ + { name: 'Rick Sanchez', gender: 'Male'}, + { name: 'Morty Smith', gender: 'Male' }, + { name: 'Creepy Little Girl', gender: 'Female'}, + { name: 'Cynthia', gender: 'Female'} + ]; + + const results = filterByOrderZA(characters); + expect (results).toEqual([ { name: 'Rick Sanchez', gender: 'Male'}, { name: 'Morty Smith', gender: 'Male' }, {name: 'Cynthia', gender: 'Female'}, {name: 'Creepy Little Girl', gender: 'Female'}]); + }); +}); + +// CALCULATE + +describe('calculate', () => { + it('Debería ser una función', () => { + expect(typeof calculate).toBe('function'); + }); + it ('debería calcular el porcentaje de mujeres con respecto a la data', () => { + const charactersFemale = [{ name: 'Creepy Little Girl', gender: 'Female'}, + { name: 'Cynthia', gender: 'Female'} + ]; + + const characters = [ + { name: 'Rick Sanchez', gender: 'Male'}, + { name: 'Morty Smith', gender: 'Male' }, + { name: 'Creepy Little Girl', gender: 'Female'}, + { name: 'Cynthia', gender: 'Female'} + ]; + + const results = calculate(charactersFemale,characters); + expect (results).toEqual('50.00'); + }); +}); \ No newline at end of file