diff --git a/README.md b/README.md index 788ab5a..a3f3cd7 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,27 @@ -# 📊 Project: Simple API 2 - -### Goal: Display data returned from an api - -### How to submit your code for review: - -- Fork and clone this repo -- Create a new branch called answer -- Checkout answer branch -- Push to your fork -- Issue a pull request -- Your pull request description should contain the following: - - (1 to 5 no 3) I completed the challenge - - (1 to 5 no 3) I feel good about my code - - Anything specific on which you want feedback! - -Example: -``` -I completed the challenge: 5 -I feel good about my code: 4 -I'm not sure if my constructors are setup cleanly... -``` +# Bangers, Only + +_Making use of the anilist API to find new anime based off of how trashy I'm feeling in the moment_ + +Description: Users can input their preferences of genre, rating, and year to receive the top results from anilist in my slick css design. + +
+ + + +
+ +## [Live Demo Here](https://godwinkamau.github.io/simple-api2/) + +
+ +## Tech Used + +HTML, CSS, JavaScript, AniList API + +
+ +## Lessons Learned + +- Using fetch requests to get data from a non-traditional API. +- A few neat CSS techniques to make the page interactive. +- Using the in-browser api-interface to build out a more complicated calling system. \ No newline at end of file diff --git "a/Screenshot 2025-11-13 at 2.19.12\342\200\257PM.png" "b/Screenshot 2025-11-13 at 2.19.12\342\200\257PM.png" new file mode 100644 index 0000000..58f2b5a Binary files /dev/null and "b/Screenshot 2025-11-13 at 2.19.12\342\200\257PM.png" differ diff --git a/css/styles.css b/css/styles.css new file mode 100644 index 0000000..3b93b4f --- /dev/null +++ b/css/styles.css @@ -0,0 +1,136 @@ +:root{ + --bg-color:#21295C; + --banner:#1B3B6F; + --lapis:#065A82; + --cerulean:#1C7293; + --popper:#9EB3C2; +} + +body { + background: var(--bg-color); + color: aliceblue; + font-family: 'Poiret One',Arial, Helvetica, sans-serif; +} + +.intro{ + display: flex; + flex-direction:column; + align-content: center; + justify-content: center; + text-align: center; + background-color: rgb(0, 0, 76); +} + +h1 { + font-family: 'Nabla'; + font-size: 2.8rem; + font-variant: small-caps; + +} + +h2 { + font-size: .8rem; + font-style: italic; +} + +.sliders { + display: flex; + align-items: center; + justify-content: space-evenly; + padding:10px; + height:130px; + margin-bottom: 20px; +} + + +fieldset { + height:100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background: linear-gradient(var(--lapis)50%,navy); +} + +.slider { + width: 400px; + align-self: stretch; +} + +legend { + font-size: 1.8rem; +} + +fieldset:first-of-type{ + align-items: flex-start; + flex-wrap: wrap; + width:25%; + gap:4px; +} + +fieldset:nth-of-type(2) { + width:30%; +} + +input[type='number']{ + height:3rem; + width:40%; + text-align: center; + font-size:1.5rem; + background-color: var(--popper); +} + +button{ + padding:15px; + background-color: var(--cerulean); +} + +.list { + display: flex; + flex-wrap: wrap; + min-height: 560px; + gap:1%; + justify-content: space-evenly; +} + +.aniContainer{ + display:flex; + visibility: hidden; + flex-direction: column; + background-color: rgb(192, 192, 192); + padding:10px; + width: 23%; + min-height: 560px; + transition: ease-in-out 2s transform; + border:1px solid navy; +} + +.aniContainer:hover{ + transform: translateY(-2px); +} + +.picture { + color: black; + height: 100%; + font-family: Arial, Helvetica, sans-serif; + + background-size: cover; + background-repeat: no-repeat; + padding:10px 0px; +} + +.words { + visibility: hidden; + background-color: rgba(255,255,255,.3); + height: 100%; + transition: all .5s ease-in; +} + +.aniTitle { + background-color: var(--lapis); +} + +.picture:hover > .words{ + visibility: visible; + backdrop-filter: blur(10px); +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..0bfda6c --- /dev/null +++ b/index.html @@ -0,0 +1,169 @@ + + + + + + Anime Recommendation Site + + + + + + + +
+

Bangers, Only! (Anime Edition)

+

Ran out of anime to watch? Impossible! Here is a tool leveraging the AnList API to help you find some new anime.

+
+
+
+ Choose your genre +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ What's your lowest score threshold (out of 100)? +
+ + +
+
+
+ What Year Would You Like? + +
+
+ Press the Button! + +
+
+
+
+
+

+
+
+
+ +

+
+
+
+
+
+

+
+
+
+ +

+
+
+
+
+
+

+
+
+
+ +

+
+
+
+
+
+

+
+
+
+ +

+
+
+
+
+
+

+
+
+
+ +

+
+
+
+
+
+

+
+
+
+ +

+
+
+
+
+
+

+
+
+
+ +

+
+
+
+
+
+

+
+
+ +

+
+
+
+ + + + \ No newline at end of file diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000..6200fdb --- /dev/null +++ b/js/main.js @@ -0,0 +1,121 @@ +document.querySelector('button').addEventListener('click',changeSettings) + + +//Had to learn this nightmare of a datastructure, I used the documentation and this medium article to get started: https://medium.com/nerd-for-tech/how-to-fetch-data-from-the-anilist-api-graphql-using-axios-77527efc8a89 +let query = ` +query Page($page: Int, $perPage: Int, $genreIn: [String], $averageScoreGreater: Int, $type: MediaType, $seasonYear: Int) { + Page(page: $page, perPage: $perPage) { + media(genre_in: $genreIn, averageScore_greater: $averageScoreGreater, type: $type, seasonYear: $seasonYear) { + title { + romaji + english + } + description + externalLinks { + url + } + coverImage { + extraLarge + } + bannerImage + } + } +} +`; + +// Define our query variables and values that will be used in the query request +let variables = { + "page": 1, + "perPage": 8, + "genreIn": [], + "averageScoreGreater": 79, + "type": "ANIME", + "seasonYear": null +}; + +// Define the config we'll need for our Api request +let url = 'https://graphql.anilist.co', + options = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + + }; + +//slider functionality +let slider = document.getElementById("scoreAvg"); +let output = document.getElementById("score"); +output.textContent = slider.value; // Display the default slider value + +// Update the current slider value +slider.oninput = function() { + output.innerHTML = this.value; + variables.averageScoreGreater = this.value; +} + +function changeSettings() { + const checkboxes = document.querySelectorAll('.genre') + checkboxes.forEach(checkbox => { + if(checkbox.checked) { + + variables.genreIn.push(checkbox.name) + + } + }) + + variables.averageScoreGreater = slider.value + + variables.seasonYear = Number(document.querySelector('#year').value) + + console.log(variables) + + options.body = JSON.stringify({ + variables: variables, + query: query + }) + + aniFetch() +} + +function aniFetch() { + + fetch(url, options) + .then(res => res.json()) + .then(data => { + // const images = document.querySelectorAll('img') + const titles = document.querySelectorAll('h3') + const descs = document.querySelectorAll('p') + const bgs = document.querySelectorAll('.picture') + + bgs.forEach((bg,idx) => { + bg.style.backgroundImage = `url('${data.data.Page.media[idx].coverImage.extraLarge}')` + + }) + titles.forEach((title,idx)=> { + title.innerText = data.data.Page.media[idx].title.english + }) + descs.forEach((desc,idx) => { + desc.innerHTML = data.data.Page.media[idx].description + }) + console.log(data) + }) + .catch(handleError); + document.querySelectorAll('.aniContainer').forEach(ani => ani.style.visibility='visible') +} + +function handleResponse(response) { + return response.json().then(function (json) { + return response.ok ? json : Promise.reject(json); + }); +} + +function handleData(data) { + console.log(data); +} + +function handleError(error) { + alert('Error, check console'); + console.error(error); +} \ No newline at end of file