Overview
Gallery reads the Unsplash API and presents it as a stacked grid with keyword search, infinite scroll, and a lightbox. It is built on Vue 3 with the Composition API and TypeScript.
The whole app is arranged around one goal: the layout must not move while content arrives. Everything else follows from that.
Motivation
I wanted to learn the Vue 3 Composition API properly rather than read about it, so I needed a small project with a real problem in it.
I picked an image grid because layout shift is the one genuinely interesting thing in an otherwise simple app. A grid that reflows every time a photo decodes is the difference between an app feeling fast and feeling broken, and getting that right is more subtle than it looks.
It is a small app built to learn a framework, and the layout-shift work in it is the part worth reading.
Decisions
The list holds either a photo or a skeleton marker. Placeholders take the exact grid slots their photos will take, so an arriving image replaces one in place and nothing below it moves. This is the whole trick, and it is why the grid holds still.
Fine auto-rows plus alternating row spans give the staggered look. No layout library and no JavaScript measuring element heights, which also means no second reflow after measurement.
A throttled scroll watcher fires the next page at the bottom, but only when no request is open, no error is showing, and the last page has not been reached. Infinite scroll without those guards hammers the API past the end of the results.
Friction
When a page request fails, the list truncates back to the last complete page so the skeletons do not sit there forever, and a retry re-requests exactly that page. Getting the rollback right took longer than the happy path.
Browse and search hit different endpoints, return different shapes, and disagree about whether a total page count exists. Normalising on the way in keeps the view identical for both, but the pagination guard has to treat an unknown total as open-ended without looping.
The state of it
The limitations, in plain terms. Every project here is something I built and use, not something I am selling.
Stack
Built in 2024 as my first project on Vue 3.
The Unsplash access key is bundled into the client, which is fine for a public demo and wrong for anything real.
There is no backend, no caching, and no error reporting beyond a retry button.
Next project