How I made my own GIF Store Using GIPHY API

How I made my own GIF Store Using GIPHY API

ยท

7 min read

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

By using Giphy API

Execution

  • Folder Structure

We need 3 files

  1. index.html
  2. style.css
  3. 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");
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}`));
})
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

ย