diff --git a/README.md b/README.md index 4942fff0..0efc8bdd 100644 --- a/README.md +++ b/README.md @@ -1,660 +1,80 @@ -# Data Lovers +# Data Lovers Rick and Morty ## Índice -* [1. Preámbulo](#1-preámbulo) -* [2. Resumen del proyecto](#2-resumen-del-proyecto) -* [3. Objetivos de aprendizaje generales](#3-objetivos-de-aprendizaje-generales) -* [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. Hito Opcional](#6-hito-opcional) -* [7. Consideraciones técnicas](#7-consideraciones-técnicas) -* [8. Objetivos de aprendizaje](#8-objetivos-de-aprendizaje) -* [9. Pistas, tips y lecturas complementarias](#8-pistas-tips-y-lecturas-complementarias) -* [10. Para considerar Project Feedback](#9-para-considerar-project-feedback) +* [1. Resumen del proyecto](#1-resumen-del-proyecto) +* [2. Historias de Usuario](#2-historias-de-usario) +* [3. Prototipos](#3-prototipos) +* [4. GitHub Pages](#4-github-pages) *** -## 1. Preámbulo +## 1. Resumen del proyecto -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. +Data Lovers Rick and Morty es una plataforma que permite a fanáticos/as y curiosos/as de la serie conocer a los personajes y sus características. -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_. +Ésta página busca ser un sitio web interactivo, donde las/os usuarias/os descubran la serie en medida que las categorías, filtros y estadísticas se van desplegando. También existe una sección de quiz donde se busca que la/el usuaria/o tenga una experiencia personalizada y se sienta partícipe de la información que se entrega a través de la presentación de la data. -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 el usuario -al lado derecho. +La interfaz cuenta con una sección de estadísticas con gráficos que indican la cantidad de personajes en las categorias género y estatus. -![json-interfaz](https://lh4.googleusercontent.com/Tn-RPXS26pVvOTdUzRT1KVaJ-_QbFs9SpcGLxSPE43fgbHaXtFgMUInuDt7kV41DkT1j8Tt29V0LxQW7SMtC6digOIhfTXSBKdwI08wUwhD3RAqlwy0hjfmhZ2BFe91mtmCSEqysfgk) +El sitio web está completamente en idioma inglés tal y como está en la data original utilizada. -## 2. Resumen del proyecto -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. +## 2. Historias de Usuario -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). +La investigación con usuarios/as nos permitió definir las historias de usuarios que guiaron el desarrollo de la interfaz, el contenido y funcionalidad de la plataforma. -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. +![Historia1](https://user-images.githubusercontent.com/109252463/200329964-900b9f53-9201-4826-8e60-1510654edcc6.png) +![Historia2](https://user-images.githubusercontent.com/109252463/200329975-b607607e-4b95-4efe-879d-c972ccc4afe9.png) +![Historia3](https://user-images.githubusercontent.com/109252463/200329973-92467beb-8f5d-4b84-a2d8-6198c3b13262.png) +![Historia4](https://user-images.githubusercontent.com/109252463/200329969-b2ae633d-e561-43b8-bfd1-b4d525a283ae.png) +![Historia5](https://user-images.githubusercontent.com/109252463/200329976-6e356145-0433-46da-bbc3-4e7ec8d9b754.png) -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: +Historia de usuario 1: +"Como usuario/a quiero ver a todos los personajes de la serie Rick and Morty" -* [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) +Historia de usuario 2: +"Quiero filtrar a los personajes por categorías género, estatus, especies" -* [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) +Historia de usuario 3: +"Quiero ordenar a los personajes alfabéticamente (A-Z y Z-A) -* [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) +Historia de usuario 4: +"Quiero buscar a los personajes por sus nombres" -* [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) +Historia de usuario 5: +"Quiero saber cuantos personajes hay en cada categoría al momento de filtrar los personajes. Y ver estadísticas generales de los personajes de la serie" -* [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) +Historia de usuario 6: +"Quiero jugar al Quiz para saber que personaje de la serie me representa" -* [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) +## 3. Prototipos -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. +Prototipo de Baja Fidelidad +![Prototipo1](https://user-images.githubusercontent.com/109252463/200330711-b8546e4b-995b-47ee-82ed-63a8ab46fe00.jpeg) -## 3. Objetivos de aprendizaje generales +Prototipo de Alta Fidelidad -Como continuación del Proyecto 1, volverás a trabajar sobre fundamentos de JavaScript, objetos y arreglos, manipulación básica del DOM, fundamentos de HTML y CSS. + - Versión Escritorio -Mientras desarrollas este proyecto, te familiarizarás con estos nuevos conceptos: -- Como trabajar con un juego de data y diseñar una interfaz para visualizar y manipular esta data. -- Uso de Flexbox en CSS para lograr hacer una página web responsiva. -- Arreglos y sus métodos para manipularlos (`filter`, `sort`, `reduce`). -- Como escribir HTML y manipular el DOM de una manera dinámica desde JavaScript. +Prototipo2 -## 4. Consideraciones generales +Prototipo3 -* Este proyecto se debe resolver en duplas. -* El proyecto será entregado subiendo tu código a GitHub (commit/push) y la - interfaz será desplegada usando [GitHub Pages](https://pages.github.com/). -* Tiempo para completarlo: Toma como referencia 4 semanas. + - Versión Mobile +Prototipo4 +Prototipo5 +Prototipo6 +Prototipo7 +Prototipo8 -## 5. Criterios de aceptación mínimos del proyecto -Los criterios para considerar que has completado este proyecto son: -### Definición del producto +## 4. GitHub Pages -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. +https://pibmunoz.github.io/DEV001-data-lovers/index.html -### Historias de usuario -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. - -Asegúrate de incluir la definición de terminado (_definition of done_) y los -Criterios de Aceptación para cada una. - -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). - -#### [Ejemplo de Historia de usuario] - -Yo como usuario [visitante del sitio] quiero poder VER todos lxs personajes/películas/deportistas para familiarizarme. - -**Criterios de Aceptación. Edita/agrega de acuerdo a tu implementación exactamente:** - ->* La UI es responsive (teléfonos y PC). ->* Todos los personajes/películas/deportistas aparecen en una misma vista, en forma ->de grilla (cuadrícula) sin ningún orden en particular. ->* La vista no tiene paginación, se hace scroll desde el primer elemento hasta el último. ->* Cada cuadrícula contiene: -> ->>* Nombre de personaje/película/deportista. ->>* [XXX] ->> ->* Al hacer _click/tap_ en cada cuadrícula sucede [XXX]. -> ->* La UI es exactamente igual al prototipo de alta fidelidad (colores, tamaños de bloques,tipo de letra, tamaño de letra, imágenes, etc. ) - -**Definición de Terminado. Edita/agrega de acuerdo a tu implementación exactamente** - ->* Todo el código está en la rama principal/main del repositorio. -> ->* La página está publicada en Github Pages y es accesible mediante un enlace/link/liga. ->* Cada estudiante del equipo ha hecho _code review_ del código escrito por la(s) otra persona(s). ->* Se hacen pruebas de usabilidad con al menos 2 usuarias y se incorporan las mejoras identificadas en la versión. - - -### Diseño de la Interfaz de Usuario - -#### Prototipo de baja fidelidad - -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`. - -#### Prototipo de alta fidelidad - -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. Hito Opcional - -Las partes "opcionales" tienen como intención permitirte profundizar un poco más sobre los objetivos de aprendizaje del proyecto. Todo en la vida tiene pros y contras, si **terminaste** con todo lo anterior y te queda tiempo, decide sabiamente si quieres invertir el tiempo en profundizar/perfeccionar o aprender cosas nuevas en el siguiente 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) -| | └── athletes -| | | ├── athletes.js -| | | ├── athletes.json -| | | ├── README.pt-BR.md -| | | └── README.md -| | └── ghibli -| | | ├── ghibli.js -| | | ├── ghibli.json -| | | ├── README.pt-BR.md -| | | └── README.md -| | └── harrypotter -| | | ├── data.js -| | | ├── harry.json -| | | ├── README.pt-BR.md -| | | └── README.md -| | ├── lol -| | | ├── lol.js -| | | ├── lol.json -| | | ├── README.pt-BR.md -| | | └── README.md -| | ├── pokemon -| | | ├── pokemon.js -| | | ├── pokemon.json -| | | ├── README.pt-BR.md -| | | └── README.md -| | └── rickandmorty -| | | ├── rickandmorty.js -| | | ├── rickandmorty.json -| | | ├── README.pt-BR.md -| | | └── README.md -| ├── data.js -| ├── index.html -| ├── main.js -| └── style.css -└── test - └── data.spec.js - -directory: 8 file: 29 -``` - -### `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 ` - - + + + + + + Data Lovers + + + + + + + +
+ + + + + + + +
+ +
+ + + + + +
+ +
+

CHARACTERS

+
+ +
+ + +
+

Order the characters

+
+ + +
+ +
+
+
+
+ + + + + +
+
+
+
+ + + + + + + +
+ + + + + \ No newline at end of file diff --git a/src/index2.html b/src/index2.html new file mode 100644 index 00000000..a91be4b1 --- /dev/null +++ b/src/index2.html @@ -0,0 +1,245 @@ + + + + + + + Data Lovers + + + + + + + +
+ + + +
+

STATISTICS

+
+
+
+
+

% Characters by gender

+ +
+
+

% Characters by status

+ +
+
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main.js b/src/main.js index 71c59f2d..333e9304 100644 --- a/src/main.js +++ b/src/main.js @@ -1,6 +1,243 @@ -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 rickandmorty from './data/rickandmorty/rickandmorty.js'; +import { filterGender, filterStatus, filterSpecies, statisticsFrequency, ordenAZ, ordenZA, buscar, quiz } from './data.js'; -console.log(example, data); +// Data por utilizar Rick and Morty +let data = rickandmorty.results; + +// let containerMobile = document.getElementById("container-mobile"); +let containerData = document.getElementById("cards"); +let sortOption = document.getElementById("sort"); +let filterOptionStatus = document.getElementById("filterStatus"); +let filterOptionGender = document.getElementById("filterGender"); +let filterOptionSpecies = document.getElementById("filterSpecies"); +let buscarPersonajes = document.querySelector("#buscar"); +let mostrarStatistics = document.getElementById("statistics"); +const clearButton = document.getElementById("clear-button"); + +// Modal inicio +const modal = document.getElementById("myModal"); +const btn = document.getElementById("myBtn"); + +// Get the element that closes the modal +const span = document.getElementsByClassName("close")[0]; + +// Usuario hace click y modal se abre +btn.onclick = function () { + modal.style.display = "block"; +}; +// Usuario hace click en (x), modal se cierra +span.onclick = function () { + modal.style.display = "none"; +}; +// Usuario hace click fuera del modal, modal se cierra +window.onclick = function (event) { + if (event.target == modal) { + modal.style.display = "none"; + } +}; +// Random function en quiz +const randomButton = document.getElementById("random-function"); +randomButton.addEventListener("click", () => { + let dataRandom; + let checked1 = document.getElementById("checkedornot"); + let checked1children = checked1.children; + let checked2 = document.getElementById("checkedornot2"); + let checked2children = checked2.children; + let mostrarCardQuiz = document.getElementById("cardPersonaje"); + // Recorre todos los children de checked1, regresa los filtrados según selección de usuario y guarda data en variable dataRandom + for (let item of checked1children) { + if (item.checked) { + console.log(filterGender(data, item.value)); + dataRandom = filterGender(data, item.value); + + } + } + // Recorre todos los children de checked2, regresa los filtrados según selección de usuario, retorna valor final de dataRandom + for (let item of checked2children) { + if (item.checked) { + dataRandom = filterStatus(dataRandom, item.value); + console.log(dataRandom); + } + } + // Ingresa valor de variable dataRandom a la función `quiz` y guarda el valor en la variable dataRandom + dataRandom = quiz(dataRandom); + // Template de card en el quiz, se inserta en el innerHTML en el div con id "mostrarCardQuiz" + let cardQuiz = `

You're sooo ${dataRandom.name}!


Name: ${dataRandom.name}


Status: ${dataRandom.status}


Species: ${dataRandom.species}


Gender: ${dataRandom.gender}


Origin: ${dataRandom["origin"].name}

`; + mostrarCardQuiz.innerHTML = cardQuiz; +}); +// Oculta información del modal cuando se envían las respuestas ingresadas en el quiz +randomButton.addEventListener("click", () => { + let x = document.getElementById("checkedornot3"); + let y = document.getElementById("checkedornot"); + let z = document.getElementById("checkedornot2"); + if (x.hidden === false && y.hidden === false && z.hidden === false) { + x.hidden = true; + y.hidden = true; + z.hidden = true; + } +}); +// fin modal + +// Template de cards personajes en container, muestra las cards en la interfaz e incluye método de ordenar AZ-ZA. Depende de la data ingresada. +const templateTarjeta = (x) => { + x.forEach((results) => { + let info = `

Name: ${results.name}


Status: ${results.status}


Species: ${results.species}


Gender: ${results.gender}


Origin: ${results["origin"].name}

`; + containerData.insertAdjacentHTML("afterbegin", info); + }) + let dataSort = x; + sortOption.addEventListener("click", () => { + if (sortOption.value == "name") { + containerData.innerHTML = "" + return templateTarjeta(ordenAZ(dataSort)); + } + else if (sortOption.value == "nameZ") { + containerData.innerHTML = "" + return templateTarjeta(ordenZA(dataSort)); + } + + }); +}; +// Define función de búsqueda de personajes por nombre. Depende de data ingresada. +const searchInput = (x) => { + buscarPersonajes.addEventListener('keyup', () => { + let dataPersonajes = buscar(x, 'name', buscarPersonajes.value); + containerData.innerHTML = ""; + return templateTarjeta(dataPersonajes); + }); +}; +// clear button +templateTarjeta(data); +clearButton.addEventListener("click", () => { + return window.location.reload(); +}); + +//funcion filtrado por Gender +filterOptionGender.addEventListener("click", () => { + let dataFiltrada; + switch (filterOptionGender.value) { + case "Female": containerData.innerHTML = ""; + dataFiltrada = filterGender(data, "Female"); + templateTarjeta(dataFiltrada); + break; + case "Male": containerData.innerHTML = ""; + dataFiltrada = filterGender(data, "Male"); + templateTarjeta(dataFiltrada); + break; + case "unknown": containerData.innerHTML = ""; + dataFiltrada = filterGender(data, "unknown"); + templateTarjeta(dataFiltrada); + break; + case "Genderless": containerData.innerHTML = ""; + dataFiltrada = filterGender(data, "Genderless"); + templateTarjeta(dataFiltrada); + break; + case "all": containerData.innerHTML = ""; + dataFiltrada = templateTarjeta(data); + templateTarjeta(dataFiltrada); + break; + } + // Función buscar en input por dataFiltrada + searchInput(dataFiltrada); + // Agrega mensaje en pantalla con estadísticas de la categoría + let options = filterOptionGender.value; + mostrarStatistics.innerHTML = `Did you know that ${options} represents ${statisticsFrequency(data, dataFiltrada)}% of the ${data.length} characters in the show`; +}); + +//funcion filtrado por Species +filterOptionSpecies.addEventListener("click", () => { + let dataFiltrada; + switch (filterOptionSpecies.value) { + case "Human": containerData.innerHTML = ""; + dataFiltrada = filterSpecies(data, "Human"); + templateTarjeta(dataFiltrada); + break; + case "Alien": containerData.innerHTML = ""; + dataFiltrada = filterSpecies(data, "Alien"); + templateTarjeta(dataFiltrada); + break; + case "Mytholog": containerData.innerHTML = ""; + dataFiltrada = filterSpecies(data, "Mytholog"); + templateTarjeta(dataFiltrada); + break; + case "unknown": containerData.innerHTML = ""; + dataFiltrada = filterSpecies(data, "unknown"); + templateTarjeta(dataFiltrada); + break; + case "Robot": containerData.innerHTML = ""; + dataFiltrada = filterSpecies(data, "Robot"); + templateTarjeta(dataFiltrada); + break; + case "Poopybutthole": containerData.innerHTML = ""; + dataFiltrada = filterSpecies(data, "Poopybutthole"); + templateTarjeta(dataFiltrada); + break; + case "Parasite": containerData.innerHTML = ""; + dataFiltrada = filterSpecies(data, "Parasite"); + templateTarjeta(dataFiltrada); + break; + case "Animal": containerData.innerHTML = ""; + dataFiltrada = filterSpecies(data, "Animal"); + templateTarjeta(dataFiltrada); + break; + case "Disease": containerData.innerHTML = ""; + dataFiltrada = filterSpecies(data, "Disease"); + templateTarjeta(dataFiltrada); + break; + case "Humanoid": containerData.innerHTML = ""; + dataFiltrada = filterSpecies(data, "Humanoid"); + templateTarjeta(dataFiltrada); + break; + case "Cronenberg": containerData.innerHTML = ""; + dataFiltrada = filterSpecies(data, "Cronenberg"); + templateTarjeta(dataFiltrada); + break; + case "Vampire": containerData.innerHTML = ""; + dataFiltrada = filterSpecies(data, "Vampire"); + templateTarjeta(dataFiltrada); + break; + case "all": containerData.innerHTML = ""; + dataFiltrada = templateTarjeta(data); + templateTarjeta(dataFiltrada); + break; + } + // Función buscar en input por dataFiltrada + searchInput(dataFiltrada); + // Agrega mensaje en pantalla con estadísticas de la categoría + let optionsSpecies = filterOptionSpecies.value; + mostrarStatistics.innerHTML = `Did you know that ${optionsSpecies} represents ${statisticsFrequency(data, dataFiltrada)}% of the ${data.length} characters in the show`; +}); + +//funcion filtrado por Status +filterOptionStatus.addEventListener("change", () => { + let dataFiltrada; + switch (filterOptionStatus.value) { + case "Alive": containerData.innerHTML = ""; + dataFiltrada = filterStatus(data, "Alive"); + templateTarjeta(dataFiltrada); + break; + case "Dead": containerData.innerHTML = ""; + dataFiltrada = filterStatus(data, "Dead"); + templateTarjeta(dataFiltrada); + break; + case "unknown": containerData.innerHTML = ""; + dataFiltrada = filterStatus(data, "unknown"); + templateTarjeta(dataFiltrada); + break; + case "all": containerData.innerHTML = ""; + dataFiltrada = templateTarjeta(data); + templateTarjeta(dataFiltrada); + break; + } + // Función buscar en input por dataFiltrada + searchInput(dataFiltrada); + // Agrega mensaje en pantalla con estadísticas de la categoría + let optionsStatus = filterOptionStatus.value; + mostrarStatistics.innerHTML = `Did you know that ${optionsStatus} represents ${statisticsFrequency(data, dataFiltrada)}% of the ${data.length} characters in the show`; +}); + +//buscar +buscarPersonajes.addEventListener('keyup', () => { + let dataPersonajes = buscar(data, 'name', buscarPersonajes.value); + containerData.innerHTML = ""; + templateTarjeta(dataPersonajes); +}); \ No newline at end of file diff --git a/src/style.css b/src/style.css index e69de29b..f80fc9e8 100644 --- a/src/style.css +++ b/src/style.css @@ -0,0 +1,609 @@ +@import url('https://fonts.googleapis.com/css2?family=Grandstander:wght@420;900&family=Nunito:ital,wght@0,400;0,700;1,400&display=swap'); + +/* Inicio */ +html, +body { + height: 100%; + width: 100%; + background-color: var(--black-color); +} + +/* Colores y fuentes utilizados */ +:root { + --black-color: black; + --grey-color: grey; + --light-green-color: #96D966; + --effects-green-color: #90BF49; + --portal-green-color: #69D91A; + --white-font-color: #FFFBFB; + --white-color: #fff; + --blue-color: #5791E7; + --border-radius: 8px; + --font-headings: 'Grandstander', cursive; + --font-body: 'Nunito', sans-serif; + ; +} + +* { + margin: 0; + padding: 0; +} + +body { + font-family: var(--font-body); +} + +/* Desktop screen */ +#home { + height: auto; + width: 20rem; + min-width: 50%; + min-height: auto; +} + +.category { + font-family: var(--font-headings); + font-weight: 900; + display: flex; + justify-content: center; + align-items: center; +} + +.card-container { + background-color: var(--grey-color); + height: 170px; + width: 170px; +} + +.card-container img { + width: 100px; +} + +.grafico { + max-width: 500px; + text-align: center; + display: flex; + flex-direction: column; + +} +.contenedorGrafico { + display: flex; + justify-content: center; +} + +canvas { + position: relative; + justify-content: center; +} + +.section-title2 { + text-align: center; + font-family: var(--font-headings); + font-weight: 900; + margin: 20px +} + + +/* INICIO GRID */ +.container { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + grid-template-rows: 1fr 1fr max-content 1fr; + gap: 8px 0px; + grid-auto-flow: row; + justify-content: space-evenly; + justify-items: center; + align-items: center; + grid-template-areas: + "nav nav nav" + "section-title section-title section-title" + "cards cards cards" + "footer footer footer"; + width: 100%; + height: 100%; +} + +nav { + grid-area: nav; + display: flex; + justify-content: center; + align-items: center; + gap: 5em; +} + +.section-title, +.category { + grid-area: section-title; + display: flex; + border-radius: 1rem; + background-color: #2d2f30; + padding: 10px; + flex-direction: column; + align-items: center; + height: auto; +} + +.cards { + grid-area: cards; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: center; + gap: 20px; + background-image: url("https://raw.githubusercontent.com/pibmunoz/DEV001-data-lovers/403f0e1407aa9a2da40770530d58fb9984474e96/src/img/rickandmortypattern.svg"); + border-radius: var(--border-radius); + padding: 20px; + max-width: 1250px; + min-width: auto; +} + +.filter { + grid-area: filter; +} + +#clear-button { + cursor: pointer; +} + +footer { + grid-area: footer; + text-align: center; + background-color: var(--light-green-color); + margin-top: 10px; + bottom: 0; + width: 100vw; + padding-top: 30px; + padding-bottom: 30px; +} + +/* FIN GRID */ +.cards img { + max-width: 10em; +} + +.card-container { + max-width: 10em; + display: none; +} + +.card { + background-color: #FFFDFD; + width: 250px; + display: flex; + flex-direction: column; + flex-wrap: wrap; + padding: 10px; + border: 1px solid var(--black-color); + box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25); + border-radius: var(--border-radius); + cursor: pointer; + transition: all 150ms ease-in-out; + box-shadow: 1px 1px 5px 0px rgba(82, 82, 82, 0.75); + position: relative; +} + +.card img { + justify-content: center; + align-self: center; + border-radius: var(--border-radius); +} + +.card p { + justify-content: flex-start; +} + +.card:hover { + top: -3px; + left: -3px; + box-shadow: 3px 3px 15px 0px rgba(82, 82, 82, 0.85); +} + +.card:active { + top: 2px; + left: 2px; +} + +button { + width: auto; + height: 3rem; + border-radius: 1rem; + margin: 1rem; + padding: .5rem; + font-family: var(--font-headings); + font-size: 1.5rem; + font-weight: 900; + color: var(--white-color); + border: #90BF49 solid 4px; + box-shadow: #D4D955 2px; + background-color: var(--black-color); +} + +@keyframes hover-button { + 0% { + box-shadow: 0px 0px 20px 3px var(--effects-green-color); + background-color: #262626; + } + + 25% { + box-shadow: 0px 0px 40px 3px var(--effects-green-color); + background-color: #595959; + } + + 50% { + box-shadow: 0px 0px 30px 3px var(--effects-green-color); + background-color: #262626; + } + + 100% { + box-shadow: 0px 0px 20px 3px var(--effects-green-color); + background-color: #0D0D0D; + } +} + +button:hover { + color: #D4D955; + border: #90BF49 solid 4px; + animation-name: hover-button; + animation-duration: 2s; + animation-iteration-count: infinite; +} + +span { + font-weight: 700; +} + +#buscar { + font-family: var(--font-body); + font-weight: 700; +} + +#buscar, +#sort { + padding: .5rem; + border-radius: .5rem; +} + +#sort { + display: block; + font-family: var(--font-headings); + background-color: var(--blue-color); +} + +#schwifty { + font-family: var(--font-headings); + font-weight: 900; + font-size: 20px; +} + +.search { + background-color: var(--portal-green-color); + display: inline-block; + margin: 5px; + padding: 10px; + box-shadow: inset 0px 4px 4px rgba(0, 0, 0, 0.25); + border-radius: var(--border-radius); + font-size: 25; + text-align: center; +} + +h2 { + color: var(--white-font-color); + text-shadow: 2px 2px darkgreen; + margin-bottom: 20px; + font-size: 40px; +} + +h3 { + color: var(--white-font-color); + margin-bottom: 10px; + text-shadow: 2px 2px 2px var(--black-color); +} + +.seccion-botones { + background-color: var(--black-color); + border-radius: var(--border-radius); + margin: 5px; + padding: 7px; + display: inline-flex; + position: relative; + align-items: center; + text-align: center; +} + +.section-title, +.seccion-botones { + display: flex; + align-items: center; + justify-content: center; + max-width: max-content; +} + +.statistics { + color: var(--white-color); + margin: 2px; +} + +/* Menu escritorio*/ +#container-mobile { + margin-top: 10px; + color: var(--white-color); + justify-content: center; + text-align: center; +} + +select { + margin: 10px 5px; + font-family: var(--font-headings); + border-color: var(--grey-color); + position: relative; + display: inline-block; + max-width: 260px; +} + + +#inMenu { + display: none; +} + +.iconoMenu { + display: none; +} + +optgroup { + border-radius: 0; + background-color: var(--black-color); + width: 100px; +} + +option { + padding: 5px; + border-color: var(--grey-color); + width: 100px; +} + +option:hover { + background-color: var(--grey-color); +} + +#container-mobile select { + font-size: 25px; + color: var(--white-color); + background-color: var(--black-color); + border: var(--portal-green-color) solid 2px; + width: 95vw; + padding: 10px; + border-radius: 3px; +} + +#container-mobile select:active { + border: var(--black-color); + background-color: var(--black-color); +} + +#container-mobile select:hover { + background-color: var(--grey-color); + border-radius: 0; +} + +a { + text-decoration: none; + color: var(--white-color); +} + +/* Inicio Sección modal box */ +.cardQuiz { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +/* The Modal (background) */ +.modal { + display: none; + /* Hidden by default */ + position: fixed; + /* Stay in place */ + z-index: 1; + /* Sit on top */ + padding: 30px; + /* Location of the box */ + left: 0; + top: 0; + width: 100vw; + /* Full width */ + height: 100%; + /* Full height */ + overflow: scroll; + /* Enable scroll if needed */ + background-color: rgb(0, 0, 0); + /* Fallback color */ + background-color: rgba(0, 0, 0, 0.4); + /* Black w/ opacity */ + color: var(--black-color); +} + +/* Modal Content */ +.modal-content { + color: var(--black-color); + background-color: #fefefe; + margin: auto; + padding: 50px; + width: 40%; + border: 1px solid #888; + border-radius: var(--border-radius); + display: flex; + flex-direction: column; + font-family: var(--font-headings); + font-size: 20px; +} + +.modal-content h2 { + color: var(--portal-green-color); + text-shadow: none; + text-transform: uppercase; + text-align: center; + font-size: 35px; + background-color: #fefefe; +} + +.modal-content h3 { + font-size: 30px; + color: var(--black-color); + text-shadow: none; + text-align: center; +} + +.modal-content button { + height: auto; + font-size: 30px; +} + +.modal-content input[type="radio"] { + border: 0px; + height: 20px; + width: 20px; + accent-color: var(--light-green-color); +} + +#cardPersonaje { + text-align: center; + justify-content: center; + align-items: center; +} + +/* The Close Button */ +.close { + color: #aaaaaa; + align-self: end; + font-size: 28px; + font-weight: bold; + font-size: 50px; +} + +.close:hover, +.close:focus { + color: var(--black-color); + text-decoration: none; + cursor: pointer; +} + +#myChart, +#myChart2 { + display: flex; + flex-direction: row; + flex-wrap: wrap; +} + +/* Fin Sección modal box */ + + +/* Inicio interfaz mobile */ +@media (max-width: 700px) { + .cards { + width: 70vw; + } + + .iconoMenu { + box-sizing: border-box; + display: inline-block; + } + + select { + display: none; + position: relative; + font-family: var(--font-headings); + padding: 5px; + } + + #inMenu { + display: none; + } + + input:checked~select { + display: block; + } + + .statisticsbtn, + .quiz { + display: flex; + position: relative; + border: solid 2px; + flex-direction: column; + } + + nav { + display: flex; + flex-direction: column; + } + + .category, + .section-title { + padding: 5px; + border-radius: 8px; + } + + #container-mobile { + display: flex; + flex-direction: column; + font-size: 30px; + border-radius: 0; + padding: 10px; + border: var(--portal-green-color) solid 3px; + } + + optgroup { + border-radius: 0; + background-color: var(--black-color); + } + + option { + padding: 5px; + } + + select option:hover { + background-color: var(--grey-color); + } + + #container-mobile select { + font-size: 25px; + color: var(--white-color); + background-color: var(--black-color); + border: var(--portal-green-color) solid 2px; + width: 95vw; + } + + #container-mobile select:active { + border: var(--black-color); + background-color: var(--black-color); + } + + #container-mobile select:hover { + background-color: var(--grey-color); + border-radius: 0; + } + + a { + text-decoration: none; + color: var(--white-color); + } + + i { + float: right; + } + + .imgRandom { + max-width: 120px; + display: flex; + align-self: center; + justify-content: center; + flex-direction: row; + } + .contenedorGrafico { + display: flex; + justify-content: center; + flex-direction: column; + } +} + +/* Fin interfaz mobile */ \ No newline at end of file diff --git a/test/data.spec.js b/test/data.spec.js index 09b1f23f..6cfd5ae6 100644 --- a/test/data.spec.js +++ b/test/data.spec.js @@ -1,23 +1,213 @@ -import { example, anotherExample } from '../src/data.js'; +import { filterGender, filterStatus, filterSpecies, statisticsFrequency, ordenAZ, ordenZA, buscar} from '../src/data.js'; +const originalData = { + "results": [ + { + "id": 1, + "name": "Rick Sanchez", + "status": "Alive", + "species": "Human", + "gender": "Male", + }, + { + "id": 2, + "name": "Morty Smith", + "status": "Alive", + "species": "Human", + "gender": "Male", + }, + { + "id": 3, + "name": "Summer Smith", + "status": "Alive", + "species": "Human", + "gender": "Female", + }, + { + "id": 16, + "name": "Amish Cyborg", + "status": "Dead", + "species": "Alien", + "gender": "Male", + + }, + ] +}; +const data = originalData.results; + -describe('example', () => { +// filterGender +describe('filterGender', () => { it('is a function', () => { - expect(typeof example).toBe('function'); + expect(typeof filterGender).toBe('function'); }); - it('returns `example`', () => { - expect(example()).toBe('example'); + it('returns personajes mujeres cuando selecciona`Female`', () => { + expect(filterGender(data, "Female")).toStrictEqual([{ + "id": 3, + "name": "Summer Smith", + "status": "Alive", + "species": "Human", + "gender": "Female", + }]); }); + + it('matches si el objeto data contiene la propiedad `gender`', () => { + expect(filterGender(data, "Female")).toHaveProperty(data, data['gender']); + }); }); +//filterSpecies +describe('filterSpecies', () => { + it('is a function', () => { + expect(typeof filterSpecies).toBe('function'); + }); + + it('returns personajes alien cuando selecciona`Alien`', () => { + expect(filterSpecies(data, "Alien")).toStrictEqual([{ + "id": 16, + "name": "Amish Cyborg", + "status": "Dead", + "species": "Alien", + "gender": "Male", + + }]); + }); +}); +// filterStatus +describe('filterStatus', () => { + it('is a function', () => { + expect(typeof filterStatus).toBe('function'); + }); -describe('anotherExample', () => { + it('returns personajes muertos cuando selecciona`Dead`', () => { + expect(filterStatus(data, "Dead")).toStrictEqual([{ + "id": 16, + "name": "Amish Cyborg", + "status": "Dead", + "species": "Alien", + "gender": "Male", + + }]); + }); + +}); +// método sort (A-Z) +describe('ordenZA', () => { it('is a function', () => { - expect(typeof anotherExample).toBe('function'); + expect(typeof ordenZA).toBe('function'); + }); + + // it('returns true si la función orden() ordena `name` de forma ascendente', () => { + // expect(ordenAZ(data)).toStrictEqual(data.sort(data.name)); + // }); + it('returns true si la función ordenAZ() ordena `name` de forma ascendente', () => { + expect(ordenZA(data)).toStrictEqual([ + { + "id": 16, + "name": "Amish Cyborg", + "status": "Dead", + "species": "Alien", + "gender": "Male", + }, + { + "id": 2, + "name": "Morty Smith", + "status": "Alive", + "species": "Human", + "gender": "Male", + }, + { + "id": 1, + "name": "Rick Sanchez", + "status": "Alive", + "species": "Human", + "gender": "Male", + }, + { + "id": 3, + "name": "Summer Smith", + "status": "Alive", + "species": "Human", + "gender": "Female", + } + + ]); }); +}); + +// método sort (Z-A) +describe('ordenAZ', () => { + it('is a function', () => { + expect(typeof ordenAZ).toBe('function'); + }); + + // it('returns true si la función sortOrdenZ() ordena `name` de forma descendente', () => { + // expect(sortOrdenZ(data)).toStrictEqual(data.sort(data.name).reverse()); + // }); + + it('returns true si la función orderZA() ordena `name` de forma descendente', () => { + expect(ordenAZ(data)).toStrictEqual([ + { + "id": 3, + "name": "Summer Smith", + "status": "Alive", + "species": "Human", + "gender": "Female", + }, + { + "id": 1, + "name": "Rick Sanchez", + "status": "Alive", + "species": "Human", + "gender": "Male", + }, + { + "id": 2, + "name": "Morty Smith", + "status": "Alive", + "species": "Human", + "gender": "Male", + }, + { + "id": 16, + "name": "Amish Cyborg", + "status": "Dead", + "species": "Alien", + "gender": "Male", + +}]); + }); +}); + +// estadísticas -P +describe('statisticsFrequency', () => { + it('is a function', () => { + expect(typeof statisticsFrequency).toBe('function'); + }); + + it('returns personajes mujeres cuando selecciona`Female`', () => { + expect(statisticsFrequency(data, filterGender (data, "Female"))).toBe(25); + }); +}); + +// Buscar +describe('buscar', () => { + it('is a function', () => { + expect(typeof buscar).toBe('function'); + }); + + it('cuando se busca Summer Smith retorna card del personaje Summer', () => { + expect(buscar(data, 'name', "Summer Smith")).toStrictEqual( + [ + { + "id": 3, + "name": "Summer Smith", + "status": "Alive", + "species": "Human", + "gender": "Female", + }] - it('returns `anotherExample`', () => { - expect(anotherExample()).toBe('OMG'); + ); }); });