DEV Community

Daniel Orner
Daniel Orner

Posted on

Building an Unsplash Slide Show on NeoCities

Unsplash is a great website that offers free images in a variety of formats and subjects. When we first went into lockdown in 2020, my home setup was two screens - my laptop, for actual work, and an external screen which is where my video calls took place, so I could still reference my work screen at the same time.

However, while a call wasn't taking place, my top screen just kind of sat there, blank. I wanted something to look at during thinking breaks. Basically I wanted a screen saver, but you can't get those going on just one screen.

Way back in the day, I had a number of personal pages on GeoCities. This revolutionary site allowed you to write your own HTML and have it hosted for free! Turns out, there's a modern version of this, called NeoCities. It allows you to create simple sites with static files that are hosted for free.

I used this post to make use of the source.unsplash.com endpoint to show a random, full-page image on my browser which I made full-screen on the external monitor. (I use Firefox for my browsing, so I just stuck Chrome up there for the slide show). I also made use of finicky so that all Google Meet links went to Chrome, while all other links stayed with Firefox.

Problem! A couple of weeks ago, Unsplash removed the source.unsplash.com endpoint. Instead, you need to use their API directly. Thankfully, the API is still free for low levels of usage, so I was able to modify the site to work with it.

The Design

Once you sign up, you'll get an API key. For these purposes, I didn't care too much about exposing it in a static site since I don't have any payment info on Unsplash and I'm not using it for anything else.

The overall design is as follows:

  • We want a "target" image div which will hold the image.
  • We will fetch 30 images (the max we can) from the API in the collection we're interested in.
  • We will loop through those images and show a new one once per minute.
  • Once we've exhausted the ones we have, we'll fetch more. This means we should in general only be making 2 API requests per hour.
  • If I don't like the image showing, I want an easy way to skip to the next one. I want to add a "refresh" button that will do that for me.

I'm going to keep this super simple. The only dependency I have is jQuery which I'm using for animations. You could easily do this with CSS animations, but I'm not as used to those.

The Implementation

First, here's the HTML:

<head>
<style>
* {
  box-sizing: border-box;
}

body {  margin: 0; background-color: black;}

.trigger {  position: fixed; top: 2rem; right: 2rem;}
  a { font-size: 2rem; color: white; transition: color 200ms ease; }
  a:hover { color: rgba(white, 0.7) }

#target {background-size: cover; background-position: center; background-repeat: no-repeat; height: 100%; width: 100%; }

</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/material-design-iconic-font/2.2.0/css/material-design-iconic-font.min.css"></link>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<div class="trigger">
  <a style="cursor: pointer;" id="refresh"><i class="zmdi zmdi-refresh-alt"></i></a>
    </div>

    <div id="target"></div>
</body>
Enter fullscreen mode Exit fullscreen mode

Now for the JavaScript.

// control the auto refresh rate -> 1000 = 1 second
window.refreshRate = 60000;
// you can change the collections ID to switch these out. Or you can use any other query from the API if you want truly random images
window.url = "https://api.unsplash.com/photos/random?w=1600&h=900&collections=879001&count=30&client_id=YOUR_API_KEY&orientation=landscape"
// use this to cache our data
window.jsonData = null;

// fetch the data, put it into the JSON blob, and pre-load the images from the data
async function fetchData() {
  const response = await fetch(window.url); 
  window.jsonData = await response.json();
  window.jsonData.forEach((image) => {
    const img = new Image();
    img.url = image.urls.full;
  });
}

// display the next image
async function nextImage() {
  const image = window.jsonData?.pop()
  if (image) { // we have more in the array
    const imageURL = image.urls.full
    $('#target').fadeOut(function() {
      $('#target').css({'background-image' : `url(${imageURL})`
    }).fadeIn(1500)
      });
  }
  else { // we've exhausted the array, go get more
    await fetchData();
    await nextImage();
  }
}

window.intervalTimer = setInterval(nextImage, refreshRate);
setTimeout(nextImage, 0);

$('#refresh').click(async function() {
  clearInterval(window.intervalTimer);
  await nextImage();
  window.intervalTimer = setInterval(nextImage, refreshRate);
});

// Hide the images on load
$('#target').hide();
Enter fullscreen mode Exit fullscreen mode

Et voila! Hope someone out there finds this helpful!

Top comments (0)