ObjectGraph Redesign Using Astro

My ideal workflow for a website would involve writing content in Markdown to be able to publish not just blog posts, but also product pages and other page types. I also take a lot of notes in Obsidian, and I appreciate their philosophy that your data should be future-proof, and what better way to ensure this than to store everything in plain text files (Markdown).

We have been around since 2004, so you can see the evolution of the website in the Wayback Machine. Below are screenshots if you prefer to scroll through them.

After 2015, we haven’t made any changes to the design as it was entirely based on an HTML template. My requirements are:

I wanted to try Astro to see if it fits the bill.

npm create astro@latest

At this point, I needed to see if Cloudflare supported Astro, so I created a repository and configured Cloudflare Pages to automatically publish whenever it detects a commit on the main branch - it worked like a charm.

Then I needed Tailwind CSS:

npx astro add tailwind

The dev toolbar was distracting me:

npx astro preferences disable devToolbar

I needed typography:

npx astro add tailwindcss/typography

Let’s get interactive with MDX:

npx astro add mdx

I also needed a Svelte component for Slideshow:

npx astro add svelte

You can see from my Astro file structure below.

VS Astro Files

I have two components so far, one for the Slideshow, which is written in Svelte.

<script>
  let currentIndex = 0;
  export let images = [];

  // Array to hold CSS classes to control visibility
  $: carouselItems = images.map((_, index) => 
    index === currentIndex ? 'block duration-700 ease-in-out' : 'hidden duration-700 ease-in-out');

  const nextImage = () => {
    currentIndex = (currentIndex + 1) % images.length;
  };

  const prevImage = () => {
    currentIndex = (currentIndex - 1 + images.length) % images.length;
  };
</script>

<div id="default-carousel" class="relative w-full bg-slate-100 rounded-lg" data-carousel="slide">
    <div class="relative h-56 md:h-[70lvh] overflow-hidden rounded-lg">
        {#each images as image, index (image)}
            <div class={carouselItems[index]} data-carousel-item>
              <img src={image} class="absolute w-full object-cover top-0 left-0" alt={`Slide ${index + 1}`}>
            </div>
        {/each}
    </div>

    <div class= "absolute z-30 flex -translate-x-1/2 bottom-5 left-1/2 space-x-3 rounded-md border p-1 bg-gray-400 border-b-slate-400">
        {#each images as _, index}
            <button
              type="button"
              class="w-3 h-3 rounded-full  {currentIndex === index ? 'bg-orange-200' : 'bg-slate-200'}"
              aria-current={currentIndex === index ? 'true' : 'false'}
              aria-label={`Slide ${index + 1}`}
              on:click={() => { currentIndex = index; }}
            ></button>
        {/each}
    </div>

    <button
      type="button"
      class="absolute top-0 start-0 z-30 flex items-center justify-center h-full px-4 cursor-pointer group focus:outline-none bg-slate-100 bg-opacity-15"
      data-carousel-prev
      on:click={prevImage}
    >
    <svg class="w-4 h-4 text-white dark:text-gray-800 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 6 10">
      <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 1 1 5l4 4"/>
  </svg>        <span class="sr-only">Previous</span>
    </button>
    <button
      type="button"
      class="absolute top-0 end-0 z-30 flex items-center justify-center h-full px-4 cursor-pointer group focus:outline-none bg-slate-100 bg-opacity-15"
      data-carousel-next
      on:click={nextImage}
    >
    <svg class="w-4 h-4 text-white dark:text-gray-800 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 6 10">
      <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 9 4-4-4-4"/>
  </svg>        <span class="sr-only">Next</span>
    </button>
</div>

And you use it by passing a list of images:

<Slideshow client:only="svelte" images={[
    '/img/geomeasuremac/sc1_2560x1600.jpg',
    '/img/geomeasuremac/sc2_2560x1600.jpg',
    '/img/geomeasuremac/sc3_2560x1600.jpg',
    '/img/geomeasuremac/sc4_2560x1600.jpg',
    '/img/geomeasuremac/jp/sc1_2560x1600.jpg',
    '/img/geomeasuremac/jp/sc2_2560x1600.jpg',
    '/img/geomeasuremac/jp/sc3_2560x1600.jpg',
    '/img/geomeasuremac/jp/sc4_2560x1600.jpg'
    ]}/>

The contact form Svelte component is also super simple. This advantage allows me to add more interactive elements in the future. My contact.mdx is very simple, as you can see below:

---
layout: ../layouts/Product.astro
title: Contact Us
description: Find out how to connect with ObjectGraph
---

### Contact

GET IN TOUCH
We welcome your comments and any business inquiries.

32 Union Square East
#1113
New York                         
NY 10003

E: [email protected] 

### Contact Form

import ContactForm from '../components/ContactForm.svelte'

<ContactForm client:only="svelte"></ContactForm>

It’s important to note that if you do not specify client:only="svelte", the interactive elements will not function properly.

Overall, I am very happy with Astro, and now I have no excuses not to write blog entries as they are as simple as creating markdown files.

By: Gavi Narra on: