Select theme appearance

Vegan Hamburg

The index page for vegan restaurants and food in Hamburg


This page is still under development. More content and features will follow. Stay tuned!

Motivation

This is a love child of my girlfriend and I. When we started, it was overly difficult to find good places to go for vegan food.

  • There were multiple listical websites, that were outdated or had very thin content.
  • Google Maps seems notoriously hard to search in
  • Many restaurants don’t have a website or have closed and still have a website

My girlfriend works in SEO and has a passion for vegan food, so we wanted to do our own spin on it. So we present: Vegan Hamburg!

Vegan Hamburg page entry displaying a friendly font welcoming visitors

Goals

The overall goal is easy to define: create a website, that makes it easy to find a vegan place for the food you desire near you (or where you want to be).

To achieve this, we outlined a few core features:

  • Clear navigation by type of food Was and place Where
  • Concise (and filterable) list of relevant locations with the most relevant information
  • A filterable map of all the locations
  • Everything should have a friendly touch to it, both in look but also in content
  • It needs to work flawlessly in mobile devices, since many users will be out and about

Here is how we did:

A list of locations, describing important features like opening hours and address

The list breaks into vertical cards on mobile

A large map shows all locations with a list to the side of locations currently in view

On mobile the list is hidden behind a button. A button for centering to the current location was added

A list of filters in a dialog allow narrowing down what you are looking for

Technical details

The main driver and key value about the website is its content, that needed to be easily customisable, flexible but also shown in multiple ways.

Content structure

To achieve this, we aligned on a structure, rigorously defined in Typescript + Zod, that is filled with content.

This allows me to work with it very easily and transform it or create dynamic pages and components derived from the content (think tags and filters), but also works well enough to input content easily for different usecases (locations on different cateogory pages have different content) while reducing errors in for example tag names.

Tags (for example Restaurant) are defined as constant array:

const WasTags = [
    "Restaurant"
] as const;

and through Typescript and Zod magic autocompleted and type checked in the file.

The map

After looking at different mapping tools, we agreed on using Leaflet, because it’s the simplest and it still gives us all the flexibility and tools that we need.

  • It’s UI is customisable through CSS
  • You can add control elements to its UI
  • It’s performant enough and uses OSM maps

A single large class handles all the rendering using Leaflet’s API, a generated GeoJSON file and plain old vanilla Typescript.

Conclusion

We’re over the moon how it turned out. The look is comfy, it’s very clean and digestible and has the right amount of features (for us). There is still a lot of content missing and it is a shit ton of work with all the locations and location changes, but it is gaining traction (rather quickly for my personal projects) and to us it feels useful. That’s all we can ask for.

Some takeaways

  • Working as a team is both rewarding and very beneficial
  • Having a SEO + content partner is a huge benefit, because you actually create something with value and people find it
  • Well structured content is key

Anyways, I hope you give it a try if it is relevant to you!

Performance update 09/2024

After adding quite a bit of content, our DOM size became quite large, which, in combination with a few other shortcomings, took a toll on the website’s performance. To alleviate this, we made a few improvements, that took our Lighthouse performance score from 80 back to 100 (most of the time :D).

Here’s what we did:

Decreasing the DOM size

Some tags have a lot of locations. This lead to quite large DOM sizes, especially because we were not careful when setting it up: To decrease it, we did the following:

  • Disabled Astro’s built in Style scoping, which was creating a lot of long data-attributes
  • Move SVGs to a seperate sprite sheet and reference them with <use>
  • Check for superflouus HTML elements and remove them

Improve rendering performance

As written above, the larger DOM size was also affecting rendering performance. To improve this, we did the following:

  • Use faster, more specific CSS selectors
  • Introduce content-visibility: auto to each location element

Break up tasks in the LocationMap

Each user interaction with the map had to check all locations and the filters, check their visibility within the map and update the markers and listings in a list. That can be a lot of work, especially on mobile devices. To alleviate this, we broke up the tasks in smaller chunks using the yieldToMainand await interactionResponse() pattern.

For more details about these measure, check out the page for Website Performance Improvements that I wrote after it.