Skip to main content
Shared components are reusable across multiple pages and layouts. They include article cards, forms, modals, and utility components.

ArticleCard

A card component for displaying blog posts with hover effects and metadata.
title
string
required
The article title
description
string
required
Brief description or excerpt of the article
dateCreated
Date
required
Publication date of the article
tags
string[]
required
Array of tag strings (displays first 3)
slug
string
required
URL slug for the article
cover_image
string
Optional cover image URL

Usage

---
import { ArticleCard } from '@/components/shared';
---

<ArticleCard
  title="Understanding Astro Components"
  description="Learn how to build reusable components in Astro"
  dateCreated={new Date('2024-01-15')}
  tags={['astro', 'javascript', 'web-dev']}
  slug="understanding-astro-components"
  cover_image="/images/blog/astro-components.jpg"
/>

Features

  • Glow effect on hover that follows mouse cursor
  • Theme-aware glow colors (gold for retro, white for dark, black for light)
  • Cover image with scale-on-hover effect
  • Smooth transitions for all interactions
  • View transitions for page navigation
  • Displays up to 3 tags with pill styling
  • Formatted date in “Month Day, Year” format
  • Line-clamped title (2 lines max)
  • Line-clamped description (3 lines max)
  • “Read more” link with arrow icon

Glow Effect Implementation

The component includes JavaScript for an interactive glow effect:
const glowColor = isRetro 
  ? 'rgba(255, 215, 0, 0.25)'    // Gold for retro
  : isDark 
    ? 'rgba(255, 255, 255, 0.12)' // White for dark
    : 'rgba(0, 0, 0, 0.08)';       // Black for light

glowEffect.style.background = 
  `radial-gradient(600px circle at ${x}px ${y}px, ${glowColor}, transparent 40%)`;

NewsletterForm

A newsletter subscription form with validation and API integration.
id
string
default:"newsletter-form"
Unique identifier for the form
showTitle
boolean
default:"true"
Whether to show the section title and description
title
string
default:"Join My Newsletter"
Custom title text
description
string
Custom description text (defaults to standard newsletter pitch)
layout
'horizontal' | 'vertical'
default:"horizontal"
Form layout orientation

Usage

---
import { NewsletterForm } from '@/components/shared';
---

<NewsletterForm />

Features

  • Email format validation
  • Required field checking
  • Client-side validation before submission
  • Error messages with auto-hide (5 seconds)
  • Success messages with auto-hide (5 seconds)
The form submits to /api/newsletter with this structure:
await fetch('/api/newsletter', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ email })
});
Expected API response:
{
  "message": "Success message",
  "error": "Error message (if failed)"
}
  • Button disabled during submission
  • Text changes to “Subscribing…”
  • Returns to “Subscribe” after completion
  • Form cleared on success

Styling Variations

The component adapts its styling based on layout: Horizontal:
  • Input and button side-by-side
  • Rounded-left input, rounded-right button
  • Compact on mobile, full-width on desktop
Vertical:
  • Stacked input and button
  • Both elements fully rounded
  • Full-width button
  • Better for narrow containers

ShareModal

A modal for sharing articles on social media with copy-to-clipboard functionality.
url
string
required
The URL to share
title
string
required
The article title
description
string
default:""
Optional description for email sharing

Usage

---
import { ShareModal } from '@/components/shared';

const url = Astro.url.href;
const { title, description } = Astro.props;
---

<ShareModal 
  url={url}
  title={title}
  description={description}
/>

Share Options

The modal includes 6 sharing platforms:
Opens Twitter intent with pre-filled text and URL

Features

  • One-click URL copying
  • Visual success feedback
  • Button text changes to “Copied!”
  • Auto-resets after 2 seconds
  • Success message with checkmark icon

Platform-Specific Styling

Each share button has unique branding:
/* X (Twitter) */
bg-sky-50 dark:bg-sky-950/30
border-sky-200 dark:border-sky-800
text-sky-600 dark:text-sky-400

/* Facebook */
bg-blue-50 dark:bg-blue-950/30
border-blue-200 dark:border-blue-800
text-blue-600 dark:text-blue-400

/* ... and so on for each platform */

ThemeSwitcher

A theme toggle button that cycles between light, dark, and retro themes.

Usage

---
import { ThemeSwitcher } from '@/components/shared';
---

<ThemeSwitcher />

Features

The component cycles through three themes in order:
  1. Light - Default light theme with standard colors
  2. Dark - Dark mode with inverted colors
  3. Retro - Custom retro theme with vintage styling
Each click advances to the next theme in the cycle.
Three icons rotate based on active theme:
  • Sun icon - Visible in light mode
  • Moon icon - Visible in dark mode
  • Retro icon - Visible in retro mode
Uses CSS transforms for smooth icon rotation:
rotate-0 scale-100      /* Active */
rotate-90 scale-0       /* Hidden */

Theme Persistence

Themes are stored in localStorage:
const setTheme = (theme: Theme) => {
  document.documentElement.classList.remove('light', 'dark', 'retro');
  document.documentElement.classList.add(theme);
  localStorage.setItem('theme', theme);
};

Theme Detection

On load, the component checks:
  1. localStorage for saved theme
  2. System preference (prefers-color-scheme) as fallback
  3. Defaults to user’s OS setting if no preference saved

Integration with Astro

Reinitializes after page transitions:
document.addEventListener('astro:after-swap', initThemeToggle);

Renders a social media icon link with hover effects.
name
string
required
Social platform name (github, twitter, linkedin, devto, email)
url
string
required
The URL to link to
icon
string
required
SVG path data for the icon
ariaLabel
string
required
Accessibility label for screen readers

Usage

---
import { SocialLink } from '@/components/shared';
---

<SocialLink
  name="github"
  url="https://github.com/username"
  icon="M12 0c-6.626 0-12 5.373-12 12..."
  ariaLabel="Visit my GitHub profile"
/>

Supported Platforms

The component maps platform names to icon components:
  • github → GitHubIcon
  • twitter → XIcon
  • linkedin → LinkedInIcon
  • devto → DevToIcon
  • email → EmailIcon

Features

  • Opens in new tab (except email)
  • noopener noreferrer for security
  • Scale animation on hover (1.1x)
  • Rounded full circle design
  • Border and shadow transitions
  • 24x24px icon size

SectionHeader

A reusable section header with accent line and subtitle.
title
string
required
The section title
subtitle
string
required
Descriptive subtitle text
accentColor
'primary' | 'secondary'
default:"primary"
Color of the accent line

Usage

---
import { SectionHeader } from '@/components/shared';
---

<SectionHeader
  title="Latest Articles"
  subtitle="Thoughts on software development and technology"
/>

<SectionHeader
  title="Featured Projects"
  subtitle="A selection of my recent work"
  accentColor="secondary"
/>

Features

  • Vertical accent bar (8px height, 4px width)
  • Responsive typography (2xl to 3xl on md+)
  • Indented subtitle (pl-7)
  • Muted foreground for subtitle
  • Bottom margin spacing (mb-16)

Other Shared Components

Decorative background gradients and patterns for visual interest. Used sparingly throughout the site for depth.
Language selection component for internationalization. Currently commented out in the navbar but ready for i18n implementation.Located at: ~/workspace/source/src/components/shared/LanguageSwitcher.astro
Similar to NewsletterForm but in a modal overlay. Useful for promotional popups or exit-intent forms.Located at: ~/workspace/source/src/components/shared/NewsletterModal.astro
Component for displaying resource links with metadata. Used on the resources page.Located at: ~/workspace/source/src/components/shared/ResourceItem.astro
Floating social media links that stick to the viewport. Can be used for persistent social sharing.Located at: ~/workspace/source/src/components/shared/StickySocials.astro

Component Export

All shared components are exported from a barrel file for convenient imports:
// ~/workspace/source/src/components/shared/index.ts

export { default as ArticleCard } from './ArticleCard.astro';
export { default as NewsletterForm } from './NewsletterForm.astro';
export { default as ShareModal } from './ShareModal.astro';
export { default as ThemeSwitcher } from './ThemeSwitcher.astro';
export { default as SocialLink } from './SocialLink.astro';
export { default as SectionHeader } from './SectionHeader.astro';
// ... other exports

Usage with Barrel Imports

---
// Import multiple components at once
import { 
  ArticleCard, 
  NewsletterForm, 
  ShareModal 
} from '@/components/shared';
---
This makes imports cleaner and more maintainable across your codebase.

Build docs developers (and LLMs) love