Compare commits

...

10 Commits

Author SHA1 Message Date
Notoric 14e2d9bdd1
Merge pull request #4 from CTEC3905-2022/pokedex
Pokedex
2024-04-16 22:01:35 +01:00
Notoric ce5104d97e Added favicon and cleaned up page 2024-04-16 21:57:36 +01:00
Notoric c6a086c5c1 Update readme 2024-04-16 21:39:19 +01:00
Notoric 14b05f95b9
Merge pull request #3 from CTEC3905-2022/pokedex
Pokedex
2024-04-16 21:38:23 +01:00
Notoric 43c3459364 Pokedex type chart 2024-04-16 21:38:04 +01:00
Notoric aa90918434 Added support for mobile and tablet 2024-04-16 17:23:52 +01:00
Notoric 6c18a0f3d3 Added text entry info box 2024-04-16 17:17:18 +01:00
Notoric 616acf0074 Added better resizing for tablet, phone and pc 2024-04-15 20:26:18 +01:00
Notoric caf9ec9187 Pokemon Popup w/ statblock 2024-04-15 17:21:08 +01:00
Notoric 636b43a261 Added a feature to display a dynamic list of pokemon that you can filter by type and generation
TODO: save current filters for page load, add popup page with info, make clickable cards, potential favourites system?
2024-03-19 02:39:47 +00:00
5 changed files with 1551 additions and 13 deletions

View File

@ -7,6 +7,24 @@
:root {
--bgColor: #ffffff;
--normal: #999999;
--fighting: #C03028;
--flying: #A890F0;
--poison: #A040A0;
--ground: #E0C068;
--rock: #B8A038;
--bug: #A8B820;
--ghost: #705898;
--steel: #B8B8D0;
--fire: #F08030;
--water: #6890F0;
--grass: #78C850;
--electric: #F8D030;
--psychic: #F85888;
--ice: #98D8D8;
--dragon: #7038F8;
--dark: #41314e;
--fairy: #EE99AC;
}
@ -33,7 +51,7 @@ body {
}
#landing {
width: 100vw;
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
@ -69,6 +87,7 @@ h1 {
font-weight: 600;
text-align: center;
user-select: none;
white-space: nowrap;
}
#titleBanner {
@ -82,7 +101,7 @@ h1 {
}
.black {
background-color: #000;
background-color: #000; /* Reference[0] https://www.w3schools.com/howto/howto_css_cutout_text.asp */
color: #fff;
mix-blend-mode: multiply;
}
@ -120,7 +139,7 @@ h1 {
background-color: #101010;
overflow: auto;
color: white;
padding: 50px;
padding: 10px;
}
p {
@ -173,6 +192,667 @@ h3 {
border-bottom: none;
}
/* FULLSCREEN STYLES */
#fullscreen {
position: fixed;
height: 100vh;
width: 100%;
background: #1118;
z-index: 100;
backdrop-filter: blur(10px);
top: 0px;
left: 0px;
display: none;
}
#fullscreen.visible {
display: flex;
}
#pokemon-display {
height: calc(100% - 90px);
width: calc(100% - 90px);
background: white;
margin: auto;
align-self: center;
display: flex;
flex-direction: column;
border-radius: 26px;
padding: 10px;
overflow-y: scroll;
min-width: 260px;
position: relative;
}
#fullscreen #close-button {
position: absolute;
top: 2px;
right: 0px;
height: 40px;
width: 40px;
border: 0;
background: #fff0;
font-size: 1.5em;
cursor: pointer;
color: white;
text-shadow: black 1px 1px 3px;
}
#pokemon-display #type-container {
position: absolute;
top: 0;
right: 0;
margin-top: 8px;
margin-right: 10px;
}
#pokemon-display .type-icon {
width: 40px;
height: 40px;
margin-left: 10px;
}
#pokemon-display #image-container {
display: flex;
justify-content: center;
align-items: center;
max-height: 475px;
background: #ddd;
background-image: linear-gradient(to right, transparent 0px, #999 1px, transparent 2px), linear-gradient(to bottom, transparent 0px, #999 1px, transparent 2px);
background-size: 35px 35px;
animation: transform 2.5s infinite;
animation-timing-function: linear;
border-radius: 15px;
margin-bottom: 8px;
}
#pokemon-display #dex-and-type-container {
display: flex;
flex-direction: column;
width: 100%;
}
#pokemon-display img {
width: 100%;
}
#description-carousel {
display: flex;
flex-direction: row;
background: #222;
border-radius: 15px;
padding-left: 28px;
padding-right: 28px;
margin: 0;
margin-bottom: 8px;
overflow: hidden;
height: fit-content;
position: relative;
overflow-y: auto;
}
#description-carousel .description-carousel-item {
color: white;
width: 100%;
flex: 0 0 100%;
height: fit-content;
margin-right: 33px;
transition: transform 0.3s ease;
}
#description-carousel #carousel-left-button {
top: 0;
left: 0;
text-align: left;
}
#description-carousel #carousel-right-button {
top: 0;
right: 0;
text-align: right;
}
#description-carousel button {
position: absolute;
height: 100%;
border: none;
background: #0000;
color: white;
width: 30px;
cursor: pointer;
}
#description-carousel button:hover {
font-size: 16px;
}
#description-carousel .description-text {
left: 0;
color: #ccc;
font-style: italic;
font-weight: 250;
}
#description-carousel .description-game {
left: 0;
font-size: 1.2em;
font-weight: 400;
padding-bottom: 10px;
border-bottom: 1px solid #ccc;
}
@keyframes transform {
from {
background-position: 0px 0px;
}
to {
background-position: 35px 35px;
}
}
#pokemon-display .pokemon-name {
font-size: 1.2em;
font-weight: 500;
margin: 0;
margin-left: 10px;
margin-bottom: 10px;
text-align: left;
}
#pokemon-display .pokemon-id {
font-size: 1.6em;
font-weight: 150;
margin: 0;
margin-left: 10px;
position: relative;
overflow: visible;
height: 0;
width: 0;
text-shadow: #fff 0px 0px 5px;
}
#statblock .stat-empty {
color: #bbb;
}
#statblock #hp .stat-filled {
color: #90d060;
}
#statblock #attack .stat-filled {
color: #ffd060;
}
#statblock #defense .stat-filled {
color: #f09040;
}
#statblock #special-attack .stat-filled {
color: #40a0f0;
}
#statblock #special-defense .stat-filled {
color: #6b30ff;
}
#statblock #speed .stat-filled {
color: #ff40ff;
}
#statblock {
background-color: #222;
color: white;
display: flex;
flex-direction: column;
align-items: center;
padding: 10px;
height: fit-content;
border-radius: 15px;
}
.stat-bar {
display: grid;
margin-bottom: 8px;
}
#statblock .stat-name {
grid-column: 1;
grid-row: 1;
}
#statblock .stat-value {
grid-column: 2;
grid-row: 1;
text-align: right;
}
#statblock .stat-graphic {
grid-column: 1 / span 2;
grid-row: 2;
}
#statblock p {
margin: 0;
}
#image-and-stats {
width: 100%;
display: flex;
flex-direction: column;
margin-bottom: 8px;
}
#type-chart-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
width: 100%;
grid-template-rows: 60px 1fr;
background-color: #222;
border-radius: 15px;
color: #ccc;
margin-bottom: 8px;
height: fit-content;
}
#type-chart-container #type-chart-title {
grid-column: 1 / span 5;
margin: 0;
margin-top: 10px;
margin-left: 10px;
color: white;
font-weight: 400;
text-align: center;
padding-bottom: 5px;
border-bottom: 1px solid #ccc;
font-size: 1.2em;
}
.type-chart-title {
display: flex;
flex-direction: column;
text-align: center;
height: 40px;
border-bottom: 1px solid #ccc;
justify-content: center;
padding: 2px;
}
.type-chart-element {
display: flex;
flex-direction: column;
justify-content: center;
color: black;
text-align: center;
margin: 2px;
height: 18px;
border-radius: 9px;
}
#noeffect-column, #doubleresist-column, #resist-column, #weak-column {
border-right: 1px solid #ccc;
}
#type-chart-container .type-chart-column {
display: flex;
flex-direction: column;
font-size: 0.6em;
padding: 0;
list-style-type: none;
}
/* POKEDEX STYLES */
#pokedex {
max-width: 1440px;
margin: auto;
margin-bottom: 50px;
}
#generation-selector, #type-selector {
overflow-x: auto;
}
#pokedex h2 {
text-align: center;
}
#generation-selector {
display: flex;
}
#generation-selector input {
display: none;
}
#generation-selector label {
display: inline-block;
padding: 10px;
margin: 10px;
min-height: 40px;
min-width: 40px;
text-align: center;
text-shadow: black 0px 0px 3px;
line-height: 40px;
border-radius: 30px;
background-color: #202020;
color: white;
cursor: pointer;
transition: background-color 0.5s;
}
#generation-selector label:hover {
background-color: #303030;
}
#generation-selector input:checked + label {
background-color: var(--bgColor);
}
#type-selector {
display: flex;
}
#type-selector input {
display: none;
}
#type-selector label {
display: inline-block;
padding: 10px;
margin: 10px;
height: 40px;
width: 40px;
text-align: center;
line-height: 40px;
border-radius: 30px;
background-color: #202020;
color: white;
cursor: pointer;
transition: background-color 0.5s;
}
#type-selector label img {
width: 40px;
height: 40px;
font-size: 10px;
}
#type-selector label:hover {
background-color: #303030;
}
#type-selector input:checked + label {
background-color: var(--bgColor);
}
#normal:checked + label {
background-color: var(--normal) !important;
}
#fighting:checked + label {
background-color: var(--fighting) !important;
}
#flying:checked + label {
background-color: var(--flying) !important;
}
#poison:checked + label {
background-color: var(--poison) !important;
}
#ground:checked + label {
background-color: var(--ground) !important;
}
#rock:checked + label {
background-color: var(--rock) !important;
}
#bug:checked + label {
background-color: var(--bug) !important;
}
#ghost:checked + label {
background-color: var(--ghost) !important;
}
#steel:checked + label {
background-color: var(--steel) !important;
}
#fire:checked + label {
background-color: var(--fire) !important;
}
#water:checked + label {
background-color: var(--water) !important;
}
#grass:checked + label {
background-color: var(--grass) !important;
}
#electric:checked + label {
background-color: var(--electric) !important;
}
#psychic:checked + label {
background-color: var(--psychic) !important;
}
#ice:checked + label {
background-color: var(--ice) !important;
}
#dragon:checked + label {
background-color: var(--dragon) !important;
}
#dark:checked + label {
background-color: var(--dark) !important;
}
#fairy:checked + label {
background-color: var(--fairy) !important;
}
.normal-primary-type {
background-color: var(--normal) !important;
}
.normal-secondary-type {
box-shadow: inset 0px -150px 100px -100px var(--normal) , 0px 0px 0px 0px transparent !important;
}
.fighting-primary-type {
background-color: var(--fighting) !important;
}
.fighting-secondary-type {
box-shadow: inset 0px -150px 100px -100px var(--fighting) , 0px 0px 0px 0px transparent !important;
}
.flying-primary-type {
background-color: var(--flying) !important;
}
.flying-secondary-type {
box-shadow: inset 0px -150px 100px -100px var(--flying) , 0px 0px 0px 0px transparent !important;
}
.poison-primary-type {
background-color: var(--poison) !important;
}
.poison-secondary-type {
box-shadow: inset 0px -150px 100px -100px var(--poison) , 0px 0px 0px 0px transparent !important;
}
.ground-primary-type {
background-color: var(--ground) !important;
}
.ground-secondary-type {
box-shadow: inset 0px -150px 100px -100px var(--ground) , 0px 0px 0px 0px transparent !important;
}
.rock-primary-type {
background-color: var(--rock) !important;
}
.rock-secondary-type {
box-shadow: inset 0px -150px 100px -100px var(--rock) , 0px 0px 0px 0px transparent !important;
}
.bug-primary-type {
background-color: var(--bug) !important;
}
.bug-secondary-type {
box-shadow: inset 0px -150px 100px -100px var(--bug) , 0px 0px 0px 0px transparent !important;
}
.ghost-primary-type {
background-color: var(--ghost) !important;
}
.ghost-secondary-type {
box-shadow: inset 0px -150px 100px -100px var(--ghost) , 0px 0px 0px 0px transparent !important;
}
.steel-primary-type {
background-color: var(--steel) !important;
}
.steel-secondary-type {
box-shadow: inset 0px -150px 100px -100px var(--steel) , 0px 0px 0px 0px transparent !important;
}
.fire-primary-type {
background-color: var(--fire) !important;
}
.fire-secondary-type {
box-shadow: inset 0px -150px 100px -100px var(--fire) , 0px 0px 0px 0px transparent !important;
}
.water-primary-type {
background-color: var(--water) !important;
}
.water-secondary-type {
box-shadow: inset 0px -150px 100px -100px var(--water) , 0px 0px 0px 0px transparent !important;
}
.grass-primary-type {
background-color: var(--grass) !important;
}
.grass-secondary-type {
box-shadow: inset 0px -150px 100px -100px var(--grass) , 0px 0px 0px 0px transparent !important;
}
.electric-primary-type {
background-color: var(--electric) !important;
}
.electric-secondary-type {
box-shadow: inset 0px -150px 100px -100px var(--electric) , 0px 0px 0px 0px transparent !important;
}
.psychic-primary-type {
background-color: var(--psychic) !important;
}
.psychic-secondary-type {
box-shadow: inset 0px -150px 100px -100px var(--psychic) , 0px 0px 0px 0px transparent !important;
}
.ice-primary-type {
background-color: var(--ice) !important;
}
.ice-secondary-type {
box-shadow: inset 0px -150px 100px -100px var(--ice) , 0px 0px 0px 0px transparent !important;
}
.dragon-primary-type {
background-color: var(--dragon) !important;
}
.dragon-secondary-type {
box-shadow: inset 0px -150px 100px -100px var(--dragon) , 0px 0px 0px 0px transparent !important;
}
.dark-primary-type {
background-color: var(--dark) !important;
}
.dark-secondary-type {
box-shadow: inset 0px -150px 100px -100px var(--dark) , 0px 0px 0px 0px transparent !important;
}
.fairy-primary-type {
background-color: var(--fairy) !important;
}
.fairy-secondary-type {
box-shadow: inset 0px -150px 100px -100px var(--fairy) , 0px 0px 0px 0px transparent !important;
}
#pokemon-container {
display: flex;
flex-direction: row;
overflow-x: auto;
overflow-y: hidden;
width: 100%;
height: 230px;
}
.pokemon-card {
height: 200px;
min-width: 300px;
background-color: #444;
margin: 10px;
border-radius: 40px;
overflow: hidden;
cursor: pointer;
}
.pokemon-card img {
position: relative;
top: -120px;
left: 100px;
height: 192px;
width: 192px;
margin: 10px;
image-rendering: pixelated;
color: black;
}
.pokemon-card .pokemon-name {
font-weight: 500;
font-size: 1.15em;
position: relative;
margin: 0;
top: 15px;
left: 15px;
z-index: 1;
text-shadow: black 1px 1px 3px;
}
.pokemon-card .pokemon-id {
font-weight: 100;
font-size: 3.5em;
position: relative;
margin: 0;
top: 15px;
left: 15px;
z-index: 0;
text-shadow: #0008 1px 1px 2px;
}
/* CAROUSEL STYLES */
#carousel {
@ -260,6 +940,49 @@ h3 {
/* applies to screens wider than 499px */
/* FULLSCREEN STYLES */
#pokemon-display {
height: calc(100% - 120px);
width: calc(100% - 120px);
border-radius: 30px;
padding: 20px;
max-height: 600px;
max-width: 900px;
padding-bottom: 12px;
}
#image-and-stats {
width: 100%;
display: grid;
grid-template-columns: 1fr 280px;
}
#pokemon-display #type-container {
margin-top: 14px;
margin-right: 20px;
}
#pokemon-display img {
grid-column: 1;
max-height: 440px;
max-width: 440px;
justify-self: center;
}
#pokemon-display #image-container {
display: flex;
grid-column: 1;
width: calc(100% - 10px);
justify-content: center;
margin: 0;
margin-right: 10px;
}
#statblock {
grid-column: 2;
width: 260px;
}
}
@ -279,11 +1002,10 @@ h3 {
}
.carousel-item {
min-width: 200px;
height: 800px;
width: 150px;
min-width: 150px;
border-radius: 74px;
width: 146px;
min-width: 146px;
border-radius: 75px;
}
.carousel-item .carousel-id {
@ -305,12 +1027,105 @@ h3 {
}
.content-column {
max-width: 1300px;
max-width: 1440px;
margin: auto;
}
/* FULLSCREEN STYLES */
#pokemon-display {
border-radius: 35px;
padding: 20px;
max-height: 755px;
max-width: 1120px;
overflow: hidden;
}
#fullscreen #close-button {
top: 20px;
right: 20px;
height: 60px;
width: 60px;
font-size: 2em;
}
#pokemon-contents {
display: grid;
grid-template-columns: 475px 1fr;
grid-column-gap: 8px;
grid-template-rows: auto;
}
#pokemon-display .pokemon-name {
font-size: 2.2em;
text-align: left;
margin-bottom: 5px;
transform: translate(0px, -8px);
}
#pokemon-display .pokemon-id {
font-size: 2.5em;
}
#pokemon-display #type-container {
margin-top: 15px;
margin-right: 25px;
}
#pokemon-display .type-icon {
width: 60px;
height: 60px;
}
#image-and-stats {
width: 475px;
display: flex;
flex-direction: column;
grid-column: 1;
grid-row: 1 / span 2;
}
#pokemon-display img {
max-height: 475px;
max-width: 475px;
height: 475px;
width: 475px;
}
#pokemon-display #image-container {
max-height: 475px;
max-width: 475px;
height: 475px;
width: 475px;
margin: 0;
margin-bottom: 8px;
}
#statblock {
flex-direction: row;
flex-wrap: wrap;
width: 455px;
font-size: 0.85em !important;
justify-content: space-between;
grid-column: 1;
grid-row: 2;
}
#description-carousel {
grid-column: 2;
height: 338px;
}
#type-chart-container {
height: 337px;
}
/* BELOW LANDING STYLES */
#below-landing {
padding: 50px;
}
.feature-showcase {
display: grid;
grid-template-columns: 1fr 1fr;
@ -344,4 +1159,18 @@ h3 {
grid-row: 3 / 3;
}
/* POKEDEX STYLES */
#generation-selector {
justify-content: center;
}
}
h1 {
margin: auto;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

View File

@ -17,8 +17,16 @@
<input id="bgColour" type="color" value="#ffffff">
</div>
</div>
<div id="fullscreen"></div>
<div id="below-landing">
<section id="pokedex">
<h2>Pokedex</h2>
<form id="generation-selector"></form>
<div id="pokemon-container"></div>
<div id="type-selector"></div>
<p>Select any creature to view its profile. You can use the top buttons to toggle creatures from different generations or use the bottom buttons to toggle creatures with a specific type.</p>
</section>
<section id="features-intro" class="content-column features">
<h2>Features</h2>
<p>

View File

@ -1,4 +1,6 @@
console.log("hello");
let controller = new AbortController(); // Reference[1] https://levelup.gitconnected.com/asynchronous-tasks-got-you-down-heres-how-to-cancel-them-480801e69ae5
let signal = controller.signal;
let activePokemonCarousel = 0;
// COLOUR PICKER BACKGROUND
@ -175,6 +177,701 @@ function transitionLake() {
transitionBackground("assets/photos/hintersee-3601004.jpg", "white");
}
// POKEDEX
async function initPokedex() {
await populateGenerations();
await populateTypes();
populatePokedex(signal);
}
async function populateGenerations() {
const container = document.getElementById("generation-selector");
const url = "https://pokeapi.co/api/v2/generation/";
const response = await fetch(url);
const data = await response.json();
let generations = [];
let generationsURL = [];
const genArray = data.results;
for (let i = 0; i < genArray.length; i++) {
const gen = genArray[i];
const genName = gen.name;
const genId = genName.split("-")[1].toUpperCase();
generations.push(genId);
generationsURL.push(gen.url);
}
for (let i = 0; i < generations.length; i++) {
const gen = generations[i];
const genButton = document.createElement("input");
genButton.type = "checkbox";
genButton.value = generationsURL[i];
genButton.id = `gen${gen}`;
if (gen === "I") {
genButton.checked = true;
} else {
genButton.checked = false;
}
container.appendChild(genButton);
const genLabel = document.createElement("label");
genLabel.htmlFor = `gen${gen}`;
genLabel.innerHTML = `${gen}`;
container.appendChild(genLabel);
}
}
function getSelectedGenerations() {
const container = document.getElementById("generation-selector");
const checkboxes = container.getElementsByTagName("input");
let selected = [];
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].checked) {
selected.push(checkboxes[i].value);
}
}
return(selected);
}
async function populateTypes() {
const container = document.getElementById("type-selector");
const url = "https://pokeapi.co/api/v2/type";
const response = await fetch(url);
const data = await response.json();
let types = [];
const typeArray = data.results;
for (let i = 0; i < typeArray.length; i++) {
const type = typeArray[i];
const typeResponse = await fetch(type.url);
const typeData = await typeResponse.json();
if (typeData.id < 1000) {
types.push(type.name);
}
}
for (let i = 0; i < types.length; i++) {
const type = types[i];
const typeButton = document.createElement("input");
typeButton.type = "checkbox";
typeButton.value = type;
typeButton.id = type;
if (type === "normal") {
typeButton.checked = true;
} else {
typeButton.checked = false;
}
container.appendChild(typeButton);
const typeImg = document.createElement("img");
typeImg.src = `https://raw.githubusercontent.com/duiker101/pokemon-type-svg-icons/5781623f147f1bf850f426cfe1874ba56a9b75ee/icons/${type}.svg`;
typeImg.alt = `${type}`;
const typeLabel = document.createElement("label");
typeLabel.htmlFor = type;
typeLabel.appendChild(typeImg);
container.appendChild(typeLabel);
}
}
function getSelectedTypes() {
const container = document.getElementById("type-selector");
const checkboxes = container.getElementsByTagName("input");
let selected = [];
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].checked) {
selected.push(checkboxes[i].value);
}
}
return selected;
}
async function populatePokedex(signal) {
const container = document.getElementById("pokemon-container");
container.innerHTML = "";
const types = await getSelectedTypes();
const generations = await getSelectedGenerations();
for (let i = 0; i < generations.length; i++) {
if (signal.aborted) {
return;
}
const url = generations[i];
const response = await fetch(url);
const data = await response.json();
const pokemon = data.pokemon_species;
for (let j = 0; j < pokemon.length; j++) {
if (signal.aborted) {
return;
}
const poke = pokemon[j];
const speciesURL = poke.url;
const speciesResponse = await fetch(speciesURL);
const speciesData = await speciesResponse.json();
const varieties = speciesData.varieties;
for (let k = 0; k < varieties.length; k++) {
if (signal.aborted) {
return;
}
const variety = varieties[k];
const varietyURL = variety.pokemon.url;
const varietyResponse = await fetch(varietyURL);
const varietyData = await varietyResponse.json();
const varietyTypes = varietyData.types;
if (types.includes(varietyTypes[0].type.name)) {
if (signal.aborted) {
return;
}
addPokemon(varietyData);
} else {
try {
if (types.includes(varietyTypes[1].type.name)) {
if (signal.aborted) {
return;
}
addPokemon(varietyData);
}
} catch {
//no second type
}
}
}
}
}
}
function addPokemon(pokemonData) {
const container = document.getElementById("pokemon-container");
// if (container.childElementCount > 100) {
// return;
// }
const pokemon = document.createElement("div");
pokemon.className = "pokemon-card";
pokemon.classList.add(pokemonData.types[0].type.name + "-primary-type");
if (pokemonData.types[1]) {
pokemon.classList.add(pokemonData.types[1].type.name + "-secondary-type");
}
pokemon.id = pokemonData.name;
const pokemonName = document.createElement("p");
pokemonName.className = "pokemon-name";
let formatedName = "";
pokemonData.name.split("-").forEach((word) => {
formatedName += word.charAt(0).toUpperCase() + word.slice(1) + " ";
});
if (formatedName.length > 20) {
formatedName = formatedName.slice(0, formatedName.length - 1);
formatedName = formatedName.slice(0, formatedName.lastIndexOf(" "));
}
pokemonName.innerHTML = formatedName;
pokemon.appendChild(pokemonName);
const pokemonId = document.createElement("p");
pokemonId.className = "pokemon-id";
pokemonId.innerHTML = `#${pokemonData.id}`;
pokemon.style.order = pokemonData.id;
pokemon.appendChild(pokemonId);
const pokemonImg = document.createElement("img");
pokemonImg.src = pokemonData.sprites.front_default;
pokemonImg.alt = pokemonData.name;
pokemon.appendChild(pokemonImg);
pokemon.addEventListener("click", () => {
const id = pokemonData.id;
createPokemonDisplay(id);
});
container.appendChild(pokemon);
}
const generationSelector = document.getElementById("generation-selector");
generationSelector.addEventListener("change", (event) => {
restartPokedexUpdate();
});
const typeSelector = document.getElementById("type-selector");
typeSelector.addEventListener("change", (event) => {
restartPokedexUpdate();
});
function restartPokedexUpdate() {
controller.abort();
setTimeout(() => {
controller = new AbortController();
signal = controller.signal;
populatePokedex(signal);
}, 250);
}
async function createPokemonDisplay(id) {
activePokemonCarousel = 0;
const fullscreenContainer = document.getElementById("fullscreen");
fullscreenContainer.className = "visible";
const pokemonDisplay = document.createElement("div");
pokemonDisplay.id = "pokemon-display";
const closeButton = document.createElement("button");
closeButton.id = "close-button";
closeButton.innerHTML = "X";
closeButton.addEventListener("click", () => {
closePokemonDisplay();
});
fullscreenContainer.addEventListener("click", (event) => {
if (event.target.id === "fullscreen") {
closePokemonDisplay();
}
});
const url = `https://pokeapi.co/api/v2/pokemon/${id}`;
const response = await fetch(url);
const data = await response.json();
const speciesurl = data.species.url;
const speciesResponse = await fetch(speciesurl);
const speciesData = await speciesResponse.json();
pokemonDisplay.className = data.types[0].type.name + "-primary-type"
const pokemonName = document.createElement("p");
pokemonName.className = "pokemon-name";
let formatedName = "";
data.name.split("-").forEach((word) => {
formatedName += word.charAt(0).toUpperCase() + word.slice(1) + " ";
});
formatedName = formatedName.slice(0, formatedName.length - 1);
pokemonName.innerHTML = formatedName;
const pokemonId = document.createElement("p");
pokemonId.className = "pokemon-id";
pokemonId.innerHTML = `#${data.id}`;
const pokemonImg = document.createElement("img");
pokemonImg.src = data.sprites.other["official-artwork"].front_default;
pokemonImg.alt = data.name;
const pokemonImgContainer = document.createElement("div");
pokemonImgContainer.id = "image-container";
pokemonImgContainer.appendChild(pokemonImg);
const pokemonStatblock = document.createElement("div");
pokemonStatblock.id = "statblock";
data.stats.forEach((stat) => {
const statBar = document.createElement("div");
statBar.className = "stat-bar";
statBar.id = stat.stat.name;
const statName = document.createElement("p");
statName.className = "stat-name";
let formatedStatName = "";
stat.stat.name.split("-").forEach((word) => {
formatedStatName += word.charAt(0).toUpperCase() + word.slice(1) + " ";
});
formatedStatName = formatedStatName.slice(0, formatedStatName.length - 1);
statName.innerHTML = formatedStatName;
const statValue = document.createElement("p");
statValue.className = "stat-value";
statValue.innerHTML = stat.base_stat;
const statGraphic = document.createElement("p");
statGraphic.className = "stat-graphic";
let stringFilled = document.createElement("span");
let stringEmpty = document.createElement("span");
const barSize = 25;
const baseStat = (stat.base_stat / 255) * barSize;
const emptyStat = barSize - baseStat;
stringFilled.innerHTML = "❚".repeat(baseStat);
stringEmpty.innerHTML = "❚".repeat(emptyStat);
stringFilled.className = "stat-filled";
stringEmpty.className = "stat-empty";
statGraphic.appendChild(stringFilled);
statGraphic.appendChild(stringEmpty);
statBar.appendChild(statGraphic);
statBar.appendChild(statName);
statBar.appendChild(statValue);
pokemonStatblock.appendChild(statBar);
});
const imageAndStats = document.createElement("div");
imageAndStats.id = "image-and-stats";
imageAndStats.appendChild(pokemonImgContainer);
imageAndStats.appendChild(pokemonStatblock);
const descriptionCarousel = document.createElement("div");
descriptionCarousel.id = "description-carousel";
let descriptionArray = [];
speciesData.flavor_text_entries.forEach((entry) => {
if (entry.language.name === "en") {
const game = entry.version.name;
const pokemonDescription = entry.flavor_text;
descriptionArray[game] = pokemonDescription;
}
});
let descriptionArrayFiltered = []
let gameArrayFiltered = []
for (const game in descriptionArray) {
let index = descriptionArrayFiltered.indexOf(descriptionArray[game]);
if (index === -1) {
descriptionArrayFiltered.push(descriptionArray[game]);
gameArrayFiltered.push(game);
} else {
gameArrayFiltered[index] += " | " + game;
}
}
descriptionArrayFiltered.forEach((description, i) => {
const carouselItem = document.createElement("div");
carouselItem.className = "description-carousel-item";
let descriptionFormatted = description;
descriptionFormatted = descriptionFormatted.replace("\u000c", " ");
descriptionFormatted = descriptionFormatted.replace("\n", " ");
descriptionFormatted = descriptionFormatted.replace("POKéMON", "Pokémon");
const descriptionText = document.createElement("p");
descriptionText.className = "description-text";
descriptionText.innerHTML = descriptionFormatted;
const descriptionGame = document.createElement("p");
descriptionGame.className = "description-game";
descriptionGame.innerHTML = gameArrayFiltered[i].toUpperCase();
carouselItem.appendChild(descriptionGame);
carouselItem.appendChild(descriptionText);
descriptionCarousel.appendChild(carouselItem);
});
const leftButton = document.createElement("button");
leftButton.id = "carousel-left-button";
leftButton.innerHTML = "◀ ";
leftButton.style.display = "none";
const rightButton = document.createElement("button");
rightButton.id = "carousel-right-button";
rightButton.innerHTML = " ▶";
leftButton.addEventListener("click", () => {
pokemonCarousel("left");
});
rightButton.addEventListener("click", () => {
pokemonCarousel("right");
});
const types = data.types;
const primaryType = types[0].type.name;
const primaryIcon = `https://raw.githubusercontent.com/duiker101/pokemon-type-svg-icons/5781623f147f1bf850f426cfe1874ba56a9b75ee/icons/${primaryType}.svg`
let secondaryType = "";
if (types[1]) {
secondaryType = types[1].type.name;
secondaryIcon = `https://raw.githubusercontent.com/duiker101/pokemon-type-svg-icons/5781623f147f1bf850f426cfe1874ba56a9b75ee/icons/${secondaryType}.svg`
} else {
secondaryType = "Monotype";
}
const typeChartContainer = document.createElement("div");
typeChartContainer.id = "type-chart-container";
const typeChartTitle = document.createElement("p");
typeChartTitle.id = "type-chart-title";
typeChartTitle.innerHTML = "Type Chart";
const noeffectColumn = document.createElement("ul");
noeffectColumn.id = "noeffect-column";
noeffectColumn.className = "type-chart-column";
const noeffectTitle = document.createElement("li");
noeffectTitle.innerHTML = "Immune";
noeffectTitle.className = "type-chart-title";
noeffectColumn.appendChild(noeffectTitle);
const doubleresistColumn = document.createElement("ul");
doubleresistColumn.id = "doubleresist-column";
doubleresistColumn.className = "type-chart-column";
const doubleresistTitle = document.createElement("li");
doubleresistTitle.innerHTML = "Double Resist";
doubleresistTitle.className = "type-chart-title";
doubleresistColumn.appendChild(doubleresistTitle);
const resistColumn = document.createElement("ul");
resistColumn.id = "resist-column";
resistColumn.className = "type-chart-column";
const resistTitle = document.createElement("li");
resistTitle.innerHTML = "Resist";
resistTitle.className = "type-chart-title";
resistColumn.appendChild(resistTitle);
const weakColumn = document.createElement("ul");
weakColumn.id = "weak-column";
weakColumn.className = "type-chart-column";
const weakTitle = document.createElement("li");
weakTitle.innerHTML = "Weak";
weakTitle.className = "type-chart-title";
weakColumn.appendChild(weakTitle);
const doubleweakColumn = document.createElement("ul");
doubleweakColumn.id = "doubleweak-column";
doubleweakColumn.className = "type-chart-column";
const doubleweakTitle = document.createElement("li");
doubleweakTitle.innerHTML = "Double Weak";
doubleweakTitle.className = "type-chart-title";
doubleweakColumn.appendChild(doubleweakTitle);
typeChartContainer.appendChild(typeChartTitle);
typeChartContainer.appendChild(noeffectColumn);
typeChartContainer.appendChild(doubleresistColumn);
typeChartContainer.appendChild(resistColumn);
typeChartContainer.appendChild(weakColumn);
typeChartContainer.appendChild(doubleweakColumn);
const primaryImg = document.createElement("img");
primaryImg.src = primaryIcon;
primaryImg.alt = primaryType;
primaryImg.className = "type-icon";
const secondaryImg = document.createElement("img");
secondaryImg.src = secondaryIcon;
secondaryImg.alt = secondaryType;
secondaryImg.className = "type-icon";
descriptionCarousel.appendChild(leftButton);
descriptionCarousel.appendChild(rightButton);
window.addEventListener("resize", () => {
transitionPokemonCarousel(activePokemonCarousel);
});
const pokemonContents = document.createElement("div");
pokemonContents.id = "pokemon-contents";
const typeContainer = document.createElement("div");
typeContainer.id = "type-container";
typeContainer.appendChild(primaryImg);
typeContainer.appendChild(secondaryImg);
// const dexAndTypeContainer = document.createElement("div");
// dexAndTypeContainer.id = "dex-and-type-container";
// dexAndTypeContainer.appendChild(descriptionCarousel);
// dexAndTypeContainer.appendChild(typeChartContainer);
pokemonDisplay.appendChild(pokemonName);
pokemonDisplay.appendChild(pokemonId);
pokemonDisplay.appendChild(typeContainer);
pokemonContents.appendChild(imageAndStats);
//pokemonContents.appendChild(dexAndTypeContainer);
pokemonContents.appendChild(descriptionCarousel);
pokemonContents.appendChild(typeChartContainer);
pokemonDisplay.appendChild(pokemonContents);
fullscreenContainer.appendChild(pokemonDisplay);
fullscreenContainer.appendChild(closeButton);
const typeChart = await calculateTypeChart(primaryType, secondaryType)
displayTypeChart(typeChart);
}
function closePokemonDisplay() {
const fullscreenContainer = document.getElementById("fullscreen");
fullscreenContainer.className = "";
const children = Array.from(fullscreenContainer.children);
children.forEach((child) => {
fullscreenContainer.removeChild(child);
});
}
function pokemonCarousel(direction) {
const items = document.getElementsByClassName("description-carousel-item").length;
const leftButton = document.getElementById("carousel-left-button");
const rightButton = document.getElementById("carousel-right-button");
if (items < 2) {
console.log("Not enough items for a carousel");
return;
}
if (direction === "left" && activePokemonCarousel === 0) {
console.log("Carousel already too far left");
return;
} else if (direction === "right" && activePokemonCarousel === items - 1) {
console.log("Carousel already too far right");
return;
}
if (direction == "left") {
activePokemonCarousel--;
} else if (direction == "right") {
activePokemonCarousel++;
}
if (activePokemonCarousel == 0) {
leftButton.style.display = "none";
} else {
leftButton.style.display = "block";
}
if (activePokemonCarousel == items - 1) {
rightButton.style.display = "none";
} else {
rightButton.style.display = "block";
}
try {
transitionPokemonCarousel(activePokemonCarousel);
} catch {
//carousel not built yet
}
}
function transitionPokemonCarousel(i) {
let offset = 0;
const items = document.getElementsByClassName("description-carousel-item");
const width = items[0].offsetWidth;
offset = (i * (width + 33));
for (const item of items) {
item.style.transform = `translateX(-${offset}px)`;
}
}
async function calculateTypeChart(primaryType, secondaryType, stat) {
let typeArray = {"normal": 0, "fighting": 0, "flying": 0, "poison": 0, "ground": 0, "rock": 0, "bug": 0, "ghost": 0, "steel": 0, "fire": 0, "water": 0, "grass": 0, "electric": 0, "psychic": 0, "ice": 0, "dragon": 0, "dark": 0, "fairy": 0};
const primaryURL = `https://pokeapi.co/api/v2/type/${primaryType}`;
const primaryResponse = await fetch(primaryURL);
const primaryData = await primaryResponse.json();
primaryData.damage_relations.double_damage_from.forEach((type) => {
typeArray[type.name] += 1;
});
primaryData.damage_relations.half_damage_from.forEach((type) => {
typeArray[type.name] -= 1;
});
primaryData.damage_relations.no_damage_from.forEach((type) => {
typeArray[type.name] -= 999;
});
if (secondaryType !== "Monotype") {
const secondaryURL = `https://pokeapi.co/api/v2/type/${secondaryType}`;
const secondaryResponse = await fetch(secondaryURL);
const secondaryData = await secondaryResponse.json();
secondaryData.damage_relations.double_damage_from.forEach((type) => {
typeArray[type.name] += 1;
});
secondaryData.damage_relations.half_damage_from.forEach((type) => {
typeArray[type.name] -= 1;
});
secondaryData.damage_relations.no_damage_from.forEach((type) => {
typeArray[type.name] -= 999;
});
}
return typeArray;
}
function displayTypeChart(typeArray) {
const resist = [];
const doubleresist = [];
const weak = [];
const doubleweak = [];
const noeffect = [];
for (const type in typeArray) {
if (typeArray[type] === -1) {
resist.push(type);
} else if (typeArray[type] === -2) {
doubleresist.push(type);
} else if (typeArray[type] === 1) {
weak.push(type);
}
else if (typeArray[type] === 2) {
doubleweak.push(type);
} else if (typeArray[type] < -100) {
noeffect.push(type);
} else {
//neutral
}
}
const noeffectColumn = document.getElementById("noeffect-column");
const doubleresistColumn = document.getElementById("doubleresist-column");
const resistColumn = document.getElementById("resist-column");
const weakColumn = document.getElementById("weak-column");
const doubleweakColumn = document.getElementById("doubleweak-column");
for (const element of document.getElementsByClassName("type-chart-element")) {
element.remove();
}
try {
noeffect.forEach((type) => {
const typeElement = document.createElement("li");
typeElement.innerHTML = type.toUpperCase();
typeElement.className = "type-chart-element";
typeElement.classList.add(type + "-primary-type");
noeffectColumn.appendChild(typeElement);
});
doubleresist.forEach((type) => {
const typeElement = document.createElement("li");
typeElement.innerHTML = type.toUpperCase();
typeElement.className = "type-chart-element";
typeElement.classList.add(type + "-primary-type");
doubleresistColumn.appendChild(typeElement);
});
resist.forEach((type) => {
const typeElement = document.createElement("li");
typeElement.innerHTML = type.toUpperCase();
typeElement.className = "type-chart-element";
typeElement.classList.add(type + "-primary-type");
resistColumn.appendChild(typeElement);
});
weak.forEach((type) => {
const typeElement = document.createElement("li");
typeElement.innerHTML = type.toUpperCase();
typeElement.className = "type-chart-element";
typeElement.classList.add(type + "-primary-type");
weakColumn.appendChild(typeElement);
});
doubleweak.forEach((type) => {
const typeElement = document.createElement("li");
typeElement.innerHTML = type.toUpperCase();
typeElement.className = "type-chart-element";
typeElement.classList.add(type + "-primary-type");
doubleweakColumn.appendChild(typeElement);
});
} catch {
//type elements not built yet
}
}
// ACCORDIAN IMAGES
function carouselExpand(i) {
@ -206,7 +903,7 @@ function initCarousel() {
// INITIALIZATION
// Set background colour to last saved value
const bgColor = document.getElementById("bgColour");
bgColor.value = localStorage.getItem("bgColour") || "#ffffff";
bgColor.value = localStorage.getItem("bgColour") || "#ff0070";
const initR = parseInt(bgColour.value.substring(1, 3), 16);
const initG = parseInt(bgColour.value.substring(3, 5), 16);
const initB = parseInt(bgColour.value.substring(5, 7), 16);
@ -214,4 +911,6 @@ changeBackground(initR, initG, initB);
document.documentElement.style.setProperty("--bgColor", bgColour.value);
// Initialize carousel
initCarousel();
carouselExpand(1);
carouselExpand(1);
// Initialize pokedex
initPokedex();

View File

@ -21,4 +21,6 @@ The `js/scripts.js` file contains a simple console.log statement to confirm that
All images inside `assets/photos` folder are from https://pixabay.com and used under the licence outlined here https://pixabay.com/service/terms/
All SVG Vectors are from https://www.svgrepo.com
All SVG Vectors are from https://www.svgrepo.com
This application makes use of the PokeAPI, which can be found at https://pokeapi.co/