Advanced Customization

Layouts, new content collections, and deeper customizations.

· 2 min read

Advanced Customization

Layouts, new content collections, and deeper customizations.

Layout Customization

Layouts are in src/layouts/:

LayoutUsed For
BaseLayout.astroAll pages (head, scripts, theme)
PageLayout.astroStandard pages
ArticleLayout.astroBlog posts
CaseStudyLayout.astroProject detail pages

Changing Content Width

Edit src/styles/global.css:

:root {
  --max-width-prose: 65ch;      /* Reading content */
  --max-width-content: 1200px;  /* Page content */
}

Adding a Sidebar

---
// src/layouts/ArticleLayout.astro
---

<BaseLayout>
  <div class="article-with-sidebar">
    <aside class="sidebar">
      <slot name="sidebar" />
    </aside>
    <article class="content">
      <slot />
    </article>
  </div>
</BaseLayout>

<style>
  .article-with-sidebar {
    display: grid;
    grid-template-columns: 250px 1fr;
    gap: var(--space-xl);
  }
  
  @media (max-width: 768px) {
    .article-with-sidebar {
      grid-template-columns: 1fr;
    }
    
    .sidebar {
      order: 2;
    }
  }
</style>

Adding New Content Collections

Step 1: Define Schema

Add to src/content.config.ts:

const certificationsCollection = defineCollection({
  loader: glob({ pattern: '**/*.mdx', base: './src/content/certifications' }),
  schema: z.object({
    title: z.string(),
    issuer: z.string(),
    date: z.coerce.date(),
    credentialUrl: z.string().url().optional(),
    expiryDate: z.coerce.date().optional(),
  }),
});

export const collections = {
  // Existing collections...
  certifications: certificationsCollection,
};

Step 2: Create Content Directory

Create src/content/certifications/ and add MDX files.

Step 3: Create Page

Create src/pages/certifications.astro:

---
import { getCollection } from 'astro:content';
import BaseLayout from '../layouts/BaseLayout.astro';
import SEO from '../components/SEO.astro';

const certifications = await getCollection('certifications');
---

<BaseLayout>
  <SEO 
    slot="head"
    title="Certifications"
    description="Professional certifications and credentials"
  />
  
  <main>
    {certifications.map((cert) => (
      <div class="certification">
        <h3>{cert.data.title}</h3>
        <p>{cert.data.issuer}</p>
      </div>
    ))}
  </main>
</BaseLayout>

Step 4: Add to Navigation

Edit src/config.ts:

nav: [
  // Existing items...
  { label: 'Certifications', href: '/certifications' },
],

Theme Toggle Customization

Location: src/components/ThemeToggle.astro

Change default theme:

// Default: respects system preference
const theme = stored || (window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark');

// Force dark as default
const theme = stored || 'dark';

Add a third theme (e.g., sepia):

  1. Add CSS variables in src/styles/global.css:
[data-theme="sepia"] {
  --color-bg: #f4ecd8;
  --color-text: #5c4b37;
  /* ... other variables */
}
  1. Update ThemeToggle to cycle through three themes.

SEO & Structured Data

The theme includes JSON-LD structured data in src/components/StructuredData.astro.

Supported Schema Types:

  • WebSite — Site-wide information
  • Article — Blog posts
  • Project — Case studies
  • Person — Author information
  • BreadcrumbList — Navigation breadcrumbs

Usage:

<StructuredData 
  type="Article" 
  data={{
    title: "Article Title",
    description: "Description",
    publishDate: new Date(),
    tags: ["tag1", "tag2"]
  }}
/>

Customizing:

Edit src/components/StructuredData.astro to add new schema types or modify existing fields.

View Transitions

Astro View Transitions provide smooth page navigation.

Lifecycle Events:

// Fires on initial load and after each navigation
document.addEventListener('astro:page-load', () => {
  // Initialize components
});

// Fires before new page content is swapped
document.addEventListener('astro:before-swap', (e) => {
  // Modify new document
});

Component Persistence:

<header class="site-header" transition:persist>
  <Navigation />
</header>

Disabling:

Remove <ClientRouter /> from src/layouts/BaseLayout.astro.

Active state detection:

const isActive = (href: string) => {
  if (href === '/') {
    return currentPath === '/';
  }
  return currentPath.startsWith(href);
};
  • Home is only active on exact root path
  • Other links are active if current path starts with their href
  • Child pages highlight their parent navigation item

Client-side updates after View Transitions:

document.addEventListener('astro:page-load', updateActiveNav);