diff --git a/Image Gallery Website/README.md b/Image Gallery Website/README.md new file mode 100644 index 0000000..85db36e --- /dev/null +++ b/Image Gallery Website/README.md @@ -0,0 +1,29 @@ +# Image-Gallery +A customizable, modular, responsive, Image Gallery website. + + +https://github.com/Ash0807/Image-Gallery/assets/93093775/cdd0e352-5497-4db8-8ad0-7a6a6b22f2d5 + + + +# Tech Stack +I used - HTML, CSS, JavaScript + +# Core Features +- Fully responsive. +- Easy to download. +- Based on any topic. +- Social sharing. +- Full screen support. +- Zoom in/out, Pinch to zoom. +- Responsive images. +- Animation +- And many more. + +# API used +```sh + api@pexels.com + + apiKey = "kQdIkN07IqZI7byq9g2H4GbRbYH7m5JCdGXjaYznNbh0ekFxadxE4wcW" + + apiUrl = `https://api.pexels.com/v1/curated?page=1' diff --git a/Image Gallery Website/index.html b/Image Gallery Website/index.html new file mode 100644 index 0000000..1d3a99b --- /dev/null +++ b/Image Gallery Website/index.html @@ -0,0 +1,60 @@ + + + + + +Ashish Image Gallery + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Image Gallery Website/script.js b/Image Gallery Website/script.js new file mode 100644 index 0000000..e2ce578 --- /dev/null +++ b/Image Gallery Website/script.js @@ -0,0 +1,86 @@ +const imageWrapper = document.querySelector(".images"); +const searchInput = document.querySelector(".search input"); +const loadMoreBtn = document.querySelector(".gallery .load-more"); +const lightbox = document.querySelector(".lightbox"); +const downloadImgBtn = lightbox.querySelector(".uil-import"); +const closeImgBtn = lightbox.querySelector(".close-icon"); + +const apiKey = "kQdIkN07IqZI7byq9g2H4GbRbYH7m5JCdGXjaYznNbh0ekFxadxE4wcW"; +const perPage = 15; +let currentPage = 1; +let searchTerm = null; + +const downloadImg = (imgUrl) => { +fetch(imgUrl).then(res => res.blob()).then(blob => { +const a = document.createElement("a"); +a.href = URL.createObjectURL(blob); +a.download = new Date().getTime(); +document.body.appendChild(a); +a.click(); +a.remove(); +}).catch(() => console.log("Failed to download image!")); +} + +const showLightbox = (name, img) => { +lightbox.querySelector("img").src = img; +lightbox.querySelector("span").innerText = name; +downloadImgBtn.setAttribute("data-img", img); +lightbox.classList.add("show"); +document.body.style.overflow = "hidden"; +} + +const hideLightbox = () => { +lightbox.classList.remove("show"); +document.body.style.overflow = "auto"; +} + +const generateHTML = (images) => { + imageWrapper.innerHTML += images.map(img => + `
  • + img +
    +
    + + ${img.photographer} +
    + +
    +
  • ` + ).join(""); +} + +const getImages = (apiURL) => { +searchInput.blur(); +loadMoreBtn.innerText = "Loading..."; +loadMoreBtn.classList.add("disabled"); +fetch(apiURL, { +headers: { Authorization: apiKey } +}).then(res => res.json()).then(data => { +generateHTML(data.photos); +loadMoreBtn.innerText = "Load More"; +loadMoreBtn.classList.remove("disabled"); +}).catch(() => console.log("Failed to load images!")); +} +const loadMoreImages = () => { +currentPage++; +let apiUrl = `https://api.pexels.com/v1/curated?page=${currentPage}&per_page=${perPage}`; +apiUrl = searchTerm ? `https://api.pexels.com/v1/search?query=${searchTerm}&page=${currentPage}&per_page=${perPage}` : apiUrl; +getImages(apiUrl); +} +const loadSearchImages = (e) => { +if(e.target.value === "") return searchTerm = null; +if(e.key === "Enter") { +currentPage = 1; +searchTerm = e.target.value; +imageWrapper.innerHTML = ""; +getImages(`https://api.pexels.com/v1/search?query=${searchTerm}&page=1&per_page=${perPage}`); +} +} + +getImages(`https://api.pexels.com/v1/curated?page=${currentPage}&per_page=${perPage}`); +loadMoreBtn.addEventListener("click", loadMoreImages); +searchInput.addEventListener("keyup", loadSearchImages); +closeImgBtn.addEventListener("click", hideLightbox); +downloadImgBtn.addEventListener("click", (e) => downloadImg(e.target.dataset.img)); \ No newline at end of file diff --git a/Image Gallery Website/search-img.jpg b/Image Gallery Website/search-img.jpg new file mode 100644 index 0000000..23fee5b Binary files /dev/null and b/Image Gallery Website/search-img.jpg differ diff --git a/Image Gallery Website/style.css b/Image Gallery Website/style.css new file mode 100644 index 0000000..a4aa15b --- /dev/null +++ b/Image Gallery Website/style.css @@ -0,0 +1,323 @@ +@import 'https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap';* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: poppins,sans-serif +} + +.search { + height: 40vh; + display: flex; + position: relative; + align-items: center; + justify-content: center +} + +.search::before,.search img,.lightbox { + left: 0; + top: 0; + width: 100%; + height: 100%; + position: absolute +} +.bottom-right { + position: absolute; + bottom: 8px; + right: 16px; +} + +.search::before { + content: ""; + z-index: 1; + background: rgba(0,0,0,.25) +} + +.search img { + object-fit: cover +} + +.search .content { + z-index: 2; + color: #fff; + padding: 0 13px; + text-align: center; + position: relative +} + +.search h1 { + font-size: 2.65rem; + font-weight: 600 +} + +.search p { + margin-top: 8px; + font-size: 1.5rem +} + +.search .search-box { + height: 55px; + margin: 45px 0; + position: relative +} + +.search-box i { + position: absolute; + left: 20px; + top: 50%; + cursor: default; + color: #8d8d8d; + font-size: 1.4rem; + transform: translateY(-50%) +} + +.search-box input { + width: 100%; + height: 100%; + outline: none; + border: none; + font-size: 1.1rem; + padding-left: 55px; + background: #fff; + border-radius: 5px +} + +.search-box input::placeholder { + color: #929292 +} + +.search-box input:focus::placeholder { + color: #bfbfbf +} + +.gallery { + display: flex; + flex-direction: column; + align-items: center +} + +.gallery .images { + gap: 15px; + max-width: 95%; + margin-top: 40px; + columns: 5 340px; + list-style: none +} + +.gallery .images .card { + display: flex; + cursor: pointer; + overflow: hidden; + position: relative; + margin-bottom: 14px; + border-radius: 30px +} + +.gallery .images img { + width: 100%; + z-index: 2; + position: relative +} + +.images .details { + position: absolute; + z-index: 4; + width: 100%; + bottom: -100px; + display: flex; + align-items: center; + padding: 25px 20px; + justify-content: space-between; + transition: bottom .1s ease; + background: linear-gradient(to top,rgba(0,0,0,0.7),transparent) +} + +.images li:hover .details { + bottom: 0 +} + +.photographer { + color: #fff; + display: flex; + align-items: center +} + +.photographer i { + font-size: 1.4rem; + margin-right: 10px +} + +.photographer span { + font-size: 1.05rem +} + +button,i { + outline: none; + border: none; + cursor: pointer; + border-radius: 5px; + transition: .2s ease +} + +.details button { + background: #fff; + font-size: 1.1rem; + padding: 3px 8px +} + +.details .download-btn:hover { + background: #f2f2f2 +} + +.gallery .load-more { + color: #fff; + background: #8a6cff; + margin: 50px 0; + font-size: 1.2rem; + padding: 12px 27px +} + +.gallery .load-more.disabled { + opacity: .6; + pointer-events: none +} + +.gallery .load-more:hover { + background: darkblue +} + +.lightbox { + z-index: 5; + position: fixed; + visibility: hidden; + background: rgba(0,0,0,.65) +} + +.lightbox.show { + visibility: visible +} + +.lightbox .wrapper { + position: fixed; + left: 50%; + top: 50%; + width: 100%; + padding: 20px; + max-width: 850px; + background: #fff; + border-radius: 6px; + opacity: 0; + pointer-events: none; + transform: translate(-50%,-50%) scale(.9); + transition: transform .1s ease +} + +.lightbox.show .wrapper { + opacity: 1; + pointer-events: auto; + transform: translate(-50%,-50%) scale(1) +} + +.wrapper header { + display: flex; + align-items: center; + justify-content: space-between +} + +header .photographer { + color: #333 +} + +header .photographer i { + font-size: 1.7rem; + cursor: auto +} + +header .photographer span { + font-size: 1.2rem +} + +header .buttons i { + height: 40px; + width: 40px; + display: inline-block; + color: #fff; + font-size: 1.2rem; + line-height: 40px; + text-align: center; + background: #8a6cff; + border-radius: 4px; + transition: .2s ease +} + +header .buttons i:first-child:hover { + background: #704dff +} + +header .buttons i:last-child { + margin-left: 10px; + font-size: 1.25rem; + background: #6c757d +} + +header .buttons i:last-child:hover { + background: #5f666d +} + +.wrapper .preview-img { + display: flex; + justify-content: center; + margin-top: 25px +} + +.preview-img .img { + max-height: 65vh +} + +.preview-img img { + width: 100%; + height: 100%; + object-fit: contain +} + +@media screen and (max-width: 688px) { + .lightbox .wrapper { + padding:12px; + max-width: calc(100% - 26px) + } + + .wrapper .preview-img { + margin-top: 15px + } + + header .buttons i:last-child { + margin-left: 7px + } + + header .photographer span,.search p { + font-size: 1.1rem + } + + .search h1 { + font-size: 1.8rem + } + + .search .search-box { + height: 50px; + margin: 30px 0 + } + + .gallery .images { + max-width: 100%; + padding: 0 13px; + margin-top: 20px + } + + .images .details { + bottom: 0 + } + + .gallery .load-more { + padding: 10px 25px; + font-size: 1.05rem + } +}