Motivation
I just wanted an open GIF store where everyone can download any GIF and share with their friends without any authentication (Open for all)
Solution
Execution
- Folder Structure
We need 3 files
- index.html
- style.css
- main.js
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Link stylesheet here -->
<link rel="stylesheet" type="text/css" href="/style.css">
<!-- Link Google Font CDN -->
<link rel="preconnect" href="https://fonts.gstatic.com">
<link
href="https://fonts.googleapis.com/css2?family=Montserrat:wght@300&family=Poppins&family=Reggae+One&display=swap"
rel="stylesheet">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<title>GIF Store</title>
</head>
<body>
<!-- Random GIF-->
<div class="randomGIF">
<img id="randomimage" src="" alt="">
</div>
<!-- Random Button -->
<div class="random">
<input type="button" id="randomButton" value="โก">
</div>
<section class="main">
<!-- Title -->
<div class="title">
<h2>GIF <span>Store</span></h2>
</div>
<!-- Search gif! -->
<div class="search">
<input type="search" id="main_gif" placeholder="๐ Search GIF..." autocomplete="off">
</div>
<!-- Trending Button -->
<div class="trending">
<input type="button" id="trendingButton" value="๐ฅ">
</div>
<!-- GIF's Categories -->
<div class="categories">
<select id="category">
<option hidden>Choose</option>
<option>Anime</option>
<option>Art & Design</option>
<option>Memes</option>
<option>News & Politics</option>
<option>Food</option>
</select>
</div>
<!-- GIF's container -->
<div class="gifs-container"></div>
</section>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.min.js">
</script>
<script src="/main.js"></script>
</html>
style.css
* {
margin: 0;
padding: 0;
}
html,
body {
background: #f1f3f8;
background: #ffffff;
}
.main.active {
filter: blur(10px);
pointer-events: none;
}
/* Title */
.title {
display: flex;
justify-content: flex-start;
align-items: flex-start;
margin: 3%;
}
.title h2 {
font-family: 'Reggae One', sans-serif;
font-size: 2.5rem;
text-shadow: 1px 1px 1px #1c1d1e;
}
.title h2 span {
color: #7049f0;
/* color:#f3542a; */
}
.search {
margin-top: 8%;
margin-bottom: 4%;
display: flex;
justify-content: center;
align-items: center;
}
.search input {
padding: 1em 1em 1em 1.3em;
width: 70%;
border-radius: 40px;
border: none;
outline: none;
background: #f1f3f8;
font-family: 'Poppins', sans-serif;
}
.search input::placeholder {
font-weight: bold;
letter-spacing: 1px;
font-size: .9rem;
}
.categories {
position: absolute;
top: 10%;
left: 90%;
}
/* GIF's Container */
.gifs-container {
margin: 5%;
column-count: 3;
}
.gifs-container>.container {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.container>div {
margin-bottom: 10%;
}
/* Image Styling */
img {
height: auto;
width: 100%;
margin-bottom: 1em;
cursor: pointer;
}
/* Button */
button {
padding: 1em 2em 1em 2em;
outline: none;
background: rgb(36, 108, 202);
border: none;
color: #f5f5f5;
text-transform: uppercase;
font-family: 'Poppins', sans-serif;
font-weight: bolder;
letter-spacing: 1px;
cursor: pointer;
text-shadow: 1px 1px 2px #1c1d1e;
border-radius: 5px;
}
button:hover {
transition: all .2s;
background: rgb(23, 66, 122);
}
/* Trending Button */
.trending,
.categories {
position: fixed;
top: 15%;
left: 90%;
transform: translate(-50%, -50%);
display: block;
}
.trending input[type="button"],
.random input[type="button"] {
padding: 1em;
border: none;
outline: none;
display: block;
height: 70px;
width: 70px;
background: #f3542a;
border-radius: 100%;
font-family: 'Poppins', sans-serif;
text-transform: uppercase;
color: #f5f5f5;
font-weight: bolder;
text-shadow: 1px 1px 2px #1d1c1e;
letter-spacing: 1px;
cursor: pointer;
transition: .2s;
text-align: center;
font-size: 1.3rem;
}
.trending input[type="button"]:hover {
background: #c51b1b;
}
/* Category */
.categories {
top: 90%;
left: 90%;
}
.categories.active {
display: none;
}
.categories select {
padding: 1em 2em 1em 2em;
font-family: 'Poppins', cursive;
background: #7049f0;
border: none;
outline: none;
border-radius: 5px;
cursor: pointer;
font-weight: bolder;
text-transform: uppercase;
color: #f5f5f5;
text-shadow: 1px 1px 1px #1d1c1e;
letter-spacing: 2px;
}
/* Random Button */
.random {
position: fixed;
top: 90%;
left: 10%;
transform: translate(-50%, -50%);
}
.random input[type="button"] {
background: #7049f0;
transition: .2s;
}
.random input[type="button"]:hover {
background: #492f9c;
}
/* Random GIF */
.randomGIF #randomimage {
position: fixed;
top: 20%;
left: 40%;
transform: translateY(-50%, -50%);
display: none;
height: 300px;
width: 300px;
z-index: 1;
}
.randomGIF #randomimage.active {
display: block;
}
/* Newly added ! */
@media (max-width:1109px) {
.categories {
left: 50%;
}
}
@media (max-width:639px) {
.gifs-container {
column-count: 2;
}
.trending {
top: 8%;
}
.random {
top: 90%;
}
.trending input[type="button"],
.random input[type="button"] {
height: 50px;
width: 50px;
font-size: .9rem;
}
.categories {
left: 50%;
}
.search input {
max-width: 100%;
}
.randomGIF #randomimage {
/* margin: 3%; */
top: 10%;
left: 8%;
transform: translateY(-50%, -50%);
height: auto;
max-width: 100%;
}
.title h2 {
font-family: .5rem;
}
}
Javascript File Breakdown
- Intialisation - Collecting all html elements for mainpulation
- Search
- Trending
- Random
- Category Wise
Data will be fetched according to the input . Here we are using fetch API to send network requests to Giphy API
Initialisation
const searchBar = document.querySelector("#main_gif");
const imageContainer = document.querySelector(".gifs-container");
const trendingButton = document.querySelector("#trendingButton");
const randomButton = document.querySelector("#randomButton");
const gifCategory = document.querySelector("#category");
const categories = document.querySelector(".categories");
const mainBody = document.querySelector(".main");
const randomGIF = document.querySelector("#randomimage");
const randomBox = document.querySelector(".randomGIF");
Search ๐
searchBar.addEventListener("input", () => {
const url = `https://api.giphy.com/v1/gifs/search?api_key=${key}&q=${searchBar.value}`;
// Fetch JSON data from base url !
fetch(url)
.then(response => response.json())
.then((result) => {
console.log(result); //Response will be actual JSON DATa
const gifData = result.data;
console.log(gifData);
let html = "";
for (let i = 0; i < gifData.length; i++) {
html += `<div class="container">
<img ondblclick="download(this)" data-image-name="${gifData[i].title}" data-image-url="${gifData[i].images.looping.mp4}" src="${gifData[i].images.preview_webp.url}"
alt="news image">
</div>`
}
imageContainer.innerHTML = html;
})
.catch(error => console.error(`Something went wrong - ${error}`));
})
Trending ๐
trendingButton.addEventListener("click", () => {
// Fetch JSON data from base url !
fetch(`https://api.giphy.com/v1/gifs/trending?api_key=${key}`)
.then(response => response.json())
.then((result) => {
console.log(result); //Response will be actual JSON DATa
const gifData = result.data;
console.log(gifData);
let html = "";
for (let i = 0; i < gifData.length; i++) {
html += `<div class="container">
<img ondblclick="download(this)" data-image-name="${gifData[i].title}" data-image-url="${gifData[i].images.looping.mp4}" src="${gifData[i].images.preview_webp.url}"
alt="news image">
</div>`
}
imageContainer.innerHTML = html;
})
.catch(error => console.error(`Something went wrong - ${error}`));
})
Random
randomButton.addEventListener("click", () => {
// CSS PART !
mainBody.classList.toggle("active");
randomGIF.classList.toggle("active");
categories.classList.toggle("active");
// Fetch JSON data from base url !
fetch(`https://api.giphy.com/v1/gifs/random?api_key=${key}`)
.then(response => response.json())
.then((result) => {
console.log(result); //Response will be actual JSON DATa
imageContainer.innerHTML = "";
randomGIF.src = result.data.images.preview_webp.url;
randomGIF.setAttribute("data-image-name", result.data.title);
randomGIF.setAttribute("data-image-url", result.data.images.looping.mp4);
randomGIF.addEventListener("dblclick", () => {
download(randomGIF);
})
// result.data.images.preview_webp.url
})
.catch(error => console.error(`Something went wrong - ${error}`));
})
Category
gifCategory.addEventListener("input", () => {
fetch(`https://api.giphy.com/v1/gifs/search?api_key=${key}&q=${gifCategory.value}`)
.then(response => response.json())
.then((result) => {
console.log(result); //Response will be actual JSON DATa
const gifData = result.data;
console.log(gifData);
let html = "";
for (let i = 0; i < gifData.length; i++) {
html += `<div class="container">
<img ondblclick="download(this)" data-image-name="${gifData[i].title}" data-image-url="${gifData[i].images.looping.mp4}" src="${gifData[i].images.preview_webp.url}" alt="news image">
</div>`
}
imageContainer.innerHTML = html;
})
.catch(error => console.error(`Something went wrong - ${error}`));
})
Now comes how to download GIF's ?
I have attached double click event listener to each gif and after double click, download function is called .
Download Function ๐ฅ
function download(element) {
console.log("Clicked :", element);
console.log("Image Name :", element.dataset.imageName);
console.log("Image URL :", element.dataset.imageUrl);
// Use axois to download GIF !
axios({
url: element.dataset.imageUrl,
method: 'GET',
responseType: 'blob'
})
.then((response) => {
const url = window.URL
.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `${element.dataset.imageName}.mp4`);
document.body.appendChild(link);
link.click();
})
}
Again Axios is a lightweight, promise-based HTTP client
Complete Javascript Code :
main.js
// Base Url : https://api.giphy.com/v1/gifs
// API-Key: <%=your_own_api_key%>
// For Search : https://api.giphy.com/v1/gifs/search
// For Random : https://api.giphy.com/v1/gifs/random
// For Trending : https://api.giphy.com/v1/gifs/trending
// Collect HTML elements
const searchBar = document.querySelector("#main_gif");
const imageContainer = document.querySelector(".gifs-container");
const trendingButton = document.querySelector("#trendingButton");
const randomButton = document.querySelector("#randomButton");
const gifCategory = document.querySelector("#category");
const categories = document.querySelector(".categories");
const mainBody = document.querySelector(".main");
const randomGIF = document.querySelector("#randomimage");
const randomBox = document.querySelector(".randomGIF");
const key = "<%=your_own_api_key%>";
// Search GIF
searchBar.addEventListener("input", () => {
const url = `https://api.giphy.com/v1/gifs/search?api_key=${key}&q=${searchBar.value}`;
// Fetch JSON data from base url !
fetch(url)
.then(response => response.json())
.then((result) => {
console.log(result); //Response will be actual JSON DATa
const gifData = result.data;
console.log(gifData);
let html = "";
for (let i = 0; i < gifData.length; i++) {
html += `<div class="container">
<img ondblclick="download(this)" data-image-name="${gifData[i].title}" data-image-url="${gifData[i].images.looping.mp4}" src="${gifData[i].images.preview_webp.url}"
alt="news image">
</div>`
}
imageContainer.innerHTML = html;
})
.catch(error => console.error(`Something went wrong - ${error}`));
})
// Trending GIF's
trendingButton.addEventListener("click", () => {
// Fetch JSON data from base url !
fetch(`https://api.giphy.com/v1/gifs/trending?api_key=${key}`)
.then(response => response.json())
.then((result) => {
console.log(result); //Response will be actual JSON DATa
const gifData = result.data;
console.log(gifData);
let html = "";
for (let i = 0; i < gifData.length; i++) {
html += `<div class="container">
<img ondblclick="download(this)" data-image-name="${gifData[i].title}" data-image-url="${gifData[i].images.looping.mp4}" src="${gifData[i].images.preview_webp.url}"
alt="news image">
</div>`
}
imageContainer.innerHTML = html;
})
.catch(error => console.error(`Something went wrong - ${error}`));
})
// Random GIF
randomButton.addEventListener("click", () => {
// CSS PART !
mainBody.classList.toggle("active");
randomGIF.classList.toggle("active");
categories.classList.toggle("active");
// Fetch JSON data from base url !
fetch(`https://api.giphy.com/v1/gifs/random?api_key=${key}`)
.then(response => response.json())
.then((result) => {
console.log(result); //Response will be actual JSON DATa
imageContainer.innerHTML = "";
randomGIF.src = result.data.images.preview_webp.url;
randomGIF.setAttribute("data-image-name", result.data.title);
randomGIF.setAttribute("data-image-url", result.data.images.looping.mp4);
randomGIF.addEventListener("dblclick", () => {
download(randomGIF);
})
// result.data.images.preview_webp.url
})
.catch(error => console.error(`Something went wrong - ${error}`));
})
// Category wise GIF's
gifCategory.addEventListener("input", () => {
fetch(`https://api.giphy.com/v1/gifs/search?api_key=${key}&q=${gifCategory.value}`)
.then(response => response.json())
.then((result) => {
console.log(result); //Response will be actual JSON DATa
const gifData = result.data;
console.log(gifData);
let html = "";
for (let i = 0; i < gifData.length; i++) {
html += `<div class="container">
<img ondblclick="download(this)" data-image-name="${gifData[i].title}" data-image-url="${gifData[i].images.looping.mp4}" src="${gifData[i].images.preview_webp.url}" alt="news image">
</div>`
}
imageContainer.innerHTML = html;
})
.catch(error => console.error(`Something went wrong - ${error}`));
})
// Download Function !
function download(element) {
console.log("Clicked :", element);
console.log("Image Name :", element.dataset.imageName);
console.log("Image URL :", element.dataset.imageUrl);
// Use axois to download GIF !
axios({
url: element.dataset.imageUrl,
method: 'GET',
responseType: 'blob'
})
.then((response) => {
const url = window.URL
.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `${element.dataset.imageName}.mp4`);
document.body.appendChild(link);
link.click();
})
}
Live Demo โ
Live - Gify Store
Want to Contribute ๐
Github Url - https://github.com/addy123d/GIF-Store
ย