I have written a reactjs web application, that displays images from a 1990-is picture archive in a modern, mobile friendly UI, that also tries to use the available space on large displays (responsive layout from bootstrap v4). The URLs of both the individual pictures and albums, contains opengraph and twitter card meta tags, that makes them appear with nice previews when being shared in social media.
In the infancy of the world wide web, back in the 1990-ies, I created a web image gallery for my photos.
The image gallery may not look like much today but actually a lot of thought went into it.
My web server at the time, had a 19200bps connection to the internet, and my web archives wasn’t the only usage of that connection, so I needed to make the thumbnails as small as possible in number of bytes, while still making it possible to see what the picture showed.
Also, back in the early 90-ies, consumer PCs had colour displays. But they rarely had true colour displays. They had SVGA displays with 4 or 8 bits per pixel.
So another thing I tried to do was to reduce the number of colours used on the thumbnails shown on the same page. A lot of expermentation went in to how the colours could be reduced while still having an idea what the thumbnail was showing.
To scan the image gallery directories, and generated linked HTML files and the thumbnails, I created a perl script.
From time to time I would like to share images from these old image galleries.
Unfortunately, the only way to share a picture is to add a link directly to the picture.
And that picture contains no description or title nor any of the fancy modern headers, that makes a preview appear in social media.
My first thought was to modify the perl script to create HTML wrappers for the individual images, that would contain a title, a description and the meta elements that makes previews possible.
But then I had a different idea: what if I left the JPEGs of the original image galleries in place, and created a new, modern webapp, that would provide a responsive layout, add title, description and navigation, and add all the meta elements that makes previews possible. The webapp should also be web crawler friendly.
One of my fundamental moments of enlightenment when learning HTML coding in the early 1990-ies, was: the image pointed to by the href attribute of an <img> could be in a different place to the HTML page (a different server, a different country or continent even).
So why not put that to good use here?
I wrote the webapp pretty much the way I got the idea, and the result can found at github: https://github.com/steinarb/oldalbum
This is an apache karaf based webapp consisting of multiple maven modules loaded together in different combinations, as outlined in Composing applications with karaf features.
A deployed version of the webapp can be found at https://oldalbum.bang.priv.no
The webapp is released to maven central and a version of the application with dummy test data, can be installed from the apache karaf command line, with the commands:
feature:repo-add mvn:no.priv.bang.oldalbum/karaf/LATEST/xml/features feature:install oldalbum-with-derby
After executing these commands, karaf will have the application running in http://localhost:8181/oldalbum on the computer the karaf process runs on.
The karaf commands shown above, uses maven (i.e. actual Java code from apache maven) to download the code of the application and all of its runtime dependencies and then load and start the Java code.
Installing a full version with a PostgreSQL database is also described in the application’s README, together with other ways of deploying the application.
Apache karaf opens for a multitude of deployment strategies. Well worth a study, if you haven’t heard about karaf before.
Personally I use the maven based approach for my local developement, for my regular production deployments and for deploying with docker. I think the maven support in karaf, is really neat.
Some highlights of the webapp:
- The frontend is written in react.js, with redux as the data model and saga providing the network calls
- Navigation to albums and images is done using react router
- The routes of the react router are dynamically based on data loaded from the database
- All react router routes are reloadable (if you reload a page you get to the same page, if you share the URL, that page will be opened)
- Styling and responsive layout is provided by bootstrap v4
- Web application deployment is done using apache maven and apache karaf
- The backend is written in Java, using the OSGi Web Whiteboard
- JAX-RS REST API is provided by eclipse jersey
- Access control for admin users is provided by apache shiro
- Data storage for the gallery is provided by JDBC databases (currently only derby and PostgreSQL are tested and supported, but no exotic SQL is used, so using a different database should be a matter of configuration)
- Database schema migration is provided by liquibase
- Different ways of deploying the application
- Deploying from inside karaf (this is what I do)
- Deploying with docker (I have verified that it works, but otherwise don’t use this myself)
- Different ways of providing the database holding the album structure:
- Having the database in PostgreSQL (this is what I do)
- Using an in-memory database and populate it from SQL in a static file read from an URL. The amount of data used by this application is quite small, so this is a possibility (this is a possibility I’ve used when deploying with docker, since removes the need to find a PostgreSQL database for the docker image to connect to. The application has a REST endpoint that can be used to read out a static file to use for imports, so you can start the application locally and add the images of the archive, and then dump the SQL and serve it from a static web resource)
I’m quite happy with the mobile phone behaviour of the webapp.
An album page looks like this on a mobile phone:
It’s possible to scroll up and down by swiping up and down. And it’s also possible to swipe sideways between albums on the same level, or by clicking on the arrows above the text with light blue background.
Sideways swiping is accomplished by using react-swipeable to add swipe detection to a <div> element. What happens when swiping to left or right is detected, is that a redux action from connected-react-router is dispatched into redux, and is picked up by the react router, and used to navigate to the new URL.
- Changes to the current location in the in the router are reflected by changes to the state in the redux store, and can be used to trigger code in a saga, when a particular location is entered
- The current location in the react router can be changed by dispatching a redux action (i.e. what is done when detecting a swipe left or right)
The authors of react-router don’t like connected-react-router. But I love the combination of redux, sagas and connected-react-router. It lets me do stuff I would have a hard time to figure out how to do, otherwise.
Clicking on one of the previews will open the image, which looks like this:
It’s possible to swipe left and right to go to the previous or next images in the album. Or you can click on the arrows just above the image.
If the mobile is tilted to landscape, the text disappears and the image is scaled up to use as much of the screen as the aspect ratio allows:
Both the album pages and the individual images, get open graph and twitter card headers that will cause a preview, with image, title and description, to appear when a URL from the image archive is pasted into a social media post, or when composing and email message in e.g. outlook (see the twitter example in the first image of this blog post).
I am less happy with how albums in the wepapp looks on a the regular web browser than I am with how albums looks on a mobile device
I have tried to use the available real estate and let the image previews float in rows instead of listing them vertically, the way it’s done on a mobile.
But the result look cluttered and untidy. Especially on a wide display. Lots of open, unused space, with the images clustered in the upper left side of the display. Ideas for layout improvements are welcome.
Here is an individual page in the modern gallery webapp. It’s an HTML page with title, description, bootstrap responsive layout, and open graph and twitter card meta tags that creates previews when the URL is shared in social media.
- All albums and individual image previews can be loaded with the URLs found in the href attributes (press F5 in the web browser on a page, and that page will be reloaded)
- The title and description in the <head> tag of the HTML file served up when loading an album or picture directly, is set to match the page loaded (i.e. not the same <title> and <description> for sll pages in the SPA)
To support all web crawlers, server side rendering of the pages would need to be done, and that won’t happen with the architecture I have chosen (Simplified delivery of react.js from apache karaf).
Not sure where this app is going and when I will be finished tinkering with it, but for now I have what I wanted, which is sharable URLs that both look nice when you open them, and create a nice preview when being shared in social media.