Implemented Hero Component and Full-Width Separator

Summary

Implemented a flexible, responsive Hero component with scroll-based animations using Intersection Observer API, supporting multiple background styles including glassmorphic effects. Also created a robust full-width separator component that spans the entire viewport width while maintaining content layout integrity.

Why Care

The Hero component provides a visually striking, accessible entry point for key pages with smooth animations that enhance user experience without external dependencies. The full-width separator solves a common layout challenge in responsive web design, allowing elements to break out of their containers and span the full viewport width. Together, these implementations demonstrate advanced CSS layout techniques and animation patterns in Astro.

Implementation

Changes Made

  • Created new component files:
    • /site/src/components/basics/Hero.astro - Main hero component with multiple background styles
    • /site/src/components/basics/HeroLoader.astro - Data-driven loader for hero content
    • /site/src/components/basics/AnimationWrapper.astro - Wrapper component for animations
    • /site/src/components/basics/separators/ThinGradientBleedSeparator.astro - Full-width separator component
    • /site/src/utils/animationUtils.ts - Animation utility using Intersection Observer API
    • /site/src/styles/animations.css - CSS animations for scroll-based effects
    • /site/src/content/messages/heroContent.json - JSON data for hero configurations
    • /site/src/pages/examples/hero.astro - Example page demonstrating hero variations
  • Modified existing files:
    • /site/src/styles/global.css - Added import for animations.css
    • /site/src/components/MainContent.astro - Restructured to support full-width elements
    • /site/src/components/basics/Header.astro - Added full-width separator to the bottom

Technical Details

Animation System

The animation system uses the Intersection Observer API to detect when elements enter the viewport:
typescript
// /site/src/utils/animationUtils.ts
export function initAnimations(): void {
  // Only run on the client
  if (typeof window === 'undefined' || typeof document === 'undefined') return;
  
  // Get all elements with data-animate attribute
  const animatedElements = document.querySelectorAll('[data-animate]');
  
  // Create observer
  observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      // If element is in viewport
      if (entry.isIntersecting) {
        const element = entry.target as HTMLElement;
        const delay = element.dataset.animateDelay || '0';
        
        // Add animation after delay
        setTimeout(() => {
          element.classList.add(ANIMATION_ACTIVE_CLASS);
        }, parseFloat(delay) * 1000);
        
        // Unobserve after animation is triggered
        observer?.unobserve(element);
      }
    });
  }, observerOptions);

  // Observe all animated elements
  animatedElements.forEach(element => {
    observer?.observe(element);
  });
}

CSS Animation Definitions

Created a comprehensive set of animations in /site/src/styles/animations.css:
css
/* Base animation setup - initially hidden */
[data-animate] {
  opacity: 0;
  transform: translate(0, 0) scale(1) rotate(0);
  transition-property: transform, opacity;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  transition-duration: 0.8s;
  will-change: transform, opacity;
  backface-visibility: hidden;
}

/* Animation active state - visible */
[data-animate].animate-active {
  opacity: 1;
  transform: translate(0, 0) scale(1) rotate(0) !important;
}

/* Fade animations */
[data-animate="fade-in"] { opacity: 0; }
[data-animate="fade-up"] { opacity: 0; transform: translateY(30px); }
[data-animate="fade-down"] { opacity: 0; transform: translateY(-30px); }
/* Additional animations defined for slide, zoom effects */

Full-Width Separator Implementation

Created a robust separator component that spans the full viewport width:
astro
<!-- /site/src/components/basics/separators/ThinGradientBleedSeparator.astro -->
<div class="separator-wrapper">
  <div class="separator--primary-bg-grd"></div>
</div>

<style>
  .separator-wrapper {
    position: relative;
    width: 100%;
    height: 2px;
    margin: 0;
    overflow: visible;
  }

  .separator--primary-bg-grd {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    width: 100vw;
    height: 2px;
    background: var(--grd__primary-bg);
  }
</style>
This solution uses:
  • A wrapper element that maintains its place in the document flow
  • An absolutely positioned child element that breaks out of the container
  • The width: 100vw property to span the full viewport width
  • left: 50% and transform: translateX(-50%) for horizontal centering
  • overflow: visible to allow the separator to extend beyond its wrapper

Hero Component Interface

The Hero component supports multiple background styles and animation options:
typescript
// /site/src/components/basics/Hero.astro
interface Props {
  title: string;
  subtitle?: string;
  description?: string;
  ctaText?: string;
  ctaUrl?: string;
  image?: { src: string; alt: string; };
  backgroundStyle?: 'gradient' | 'dark' | 'glass' | 'glassmorphic' | 'glassmorphic-vivid';
  alignment?: 'left' | 'center';
  fullBleed?: boolean;
  classes?: string;
  animate?: boolean;
}

Glassmorphic Effects

Implemented sophisticated blob styling for glassmorphic variants:
css
/* /site/src/components/basics/Hero.astro */
.blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(40px);
  opacity: 0.15;
  background: var(--grd--lossless-eastern-crimson);
}

.glassmorphic-blobs--vivid .blob {
  opacity: 0.25;
  filter: blur(60px);
}

Integration Points

  • Integrates with the existing design system using CSS variables from lossless-theme.css
  • Works with Astro's view transitions via event listeners:
    javascript
    document.addEventListener('astro:page-load', resetAnimations);
    document.addEventListener('astro:after-swap', resetAnimations);
  • Data-driven approach allows content to be managed through JSON files
  • Animation system can be reused across other components
  • Separator component can be used throughout the site for consistent visual dividers

Accessibility

  • Implemented reduced motion preferences support:
    css
    @media (prefers-reduced-motion: reduce) {
      [data-animate] {
        transition-duration: 0.1s;
      }
    }
  • Added animate prop to allow disabling animations programmatically
  • Maintained proper color contrast for text readability
  • Ensured all interactive elements are keyboard accessible
  • Separator implementation maintains document flow for proper screen reader navigation

Documentation

  • Added comprehensive JSDoc comments to all components and utilities
  • Created example page at /site/src/pages/examples/hero.astro demonstrating all variants
  • Updated the Hero component prompt with detailed implementation instructions
  • Created an Issue Resolution Breadcrumb document for the full-width separator implementation at /content/lost-in-public/prompts/workflow/Full-Width-Separator-Issue-Resolution.md