Building an Unsplash Slide Show on NeoCities
Daniel Orner
Posted on July 7, 2023
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>
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();
Et voila! Hope someone out there finds this helpful!
Posted on July 7, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.